Version 2.6.0-dev.0.0

Merge commit 'f1f709ec1121113e52ec7f7e9cd2bf5a33fe5c37' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c048c13..c6555d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,7 +22,7 @@
 
 ```dart
 // Example: these are now valid constants.
-const i = 3;
+const Object i = 3;
 const list = [i as int];
 const set = {if (list is List<int>) ...list};
 const map = {if (i is int) i : "int"};
@@ -161,11 +161,14 @@
 
 #### Linter
 
-The Linter was updated to `0.1.96`, which includes:
+The Linter was updated to `0.1.97+1`, which includes:
 
-* fixed false positives in `unnecessary_parens`
-* various changes to migrate to preferred analyzer APIs
-* rule test fixes
+* internal migration away from using analyzer `resolutionMap`
+* various fixes and improvements to anticipate support for extension-methods
+* new lint: `camel_case_extensions`
+* rule template generation improvements
+* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
+* extended `avoid_slow_async_io` to flag async `Directory` methods
 
 #### Dartdoc
 
@@ -188,6 +191,15 @@
 [37551]: https://github.com/dart-lang/sdk/issues/37551
 [35121]: https://github.com/dart-lang/sdk/issues/35121
 
+### Dart Dev Compiler (DDC)
+
+Callbacks passed to JS and wrapped with `allowInterop` or
+`allowInteropCaptureThis` are now strict about argument counts and argument
+types. This may mean that tests which were previously passing and relying on
+loose argument checking (too many or too few arguments, or arguments with too
+specific types like `List<Something>` instead of `List<dynamic>`) may start
+failing. This changes makes DDC behave more like dart2js with the default flags.
+
 ## 2.4.0 - 2019-06-27
 
 ### Core libraries
diff --git a/DEPS b/DEPS
index 94d2e6e..6033eca 100644
--- a/DEPS
+++ b/DEPS
@@ -54,7 +54,7 @@
   "gperftools_revision": "e9ab4c53041ac62feefbbb076d326e9a77dd1567",
 
   # Revisions of /third_party/* dependencies.
-  "args_tag": "1.4.4",
+  "args_tag": "1.5.0",
   "async_tag": "2.0.8",
   "bazel_worker_tag": "bazel_worker-v0.1.20",
   "benchmark_harness_tag": "81641290dea44c34138a109a37e215482f405f81",
@@ -84,7 +84,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
   "dart_style_tag": "1.2.8",  # Please see the note above before updating.
 
-  "dartdoc_tag" : "0.28.4",
+  "dartdoc_rev" : "6934accd88c29a73cae26d0c4def3323efc2119c",
   "fixnum_tag": "0.10.9",
   "glob_tag": "1.1.7",
   "html_tag" : "0.14.0+1",
@@ -99,7 +99,7 @@
   "intl_tag": "0.15.7",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "2.0.9",
-  "linter_tag": "0.1.96",
+  "linter_tag": "0.1.97+1",
   "logging_tag": "0.11.3+2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_tag": "2.0.3",
@@ -138,7 +138,7 @@
   "term_glyph_tag": "1.0.1",
   "test_reflective_loader_tag": "0.1.8",
   "test_tag": "test-v1.6.4",
-  "tflite_native_rev": "65889224d8ee32ceaf4f78d8d29fd59750e1b817",
+  "tflite_native_rev": "06e533a9747306d1114c53427cc67eda080f51f9",
   "typed_data_tag": "1.1.6",
   "unittest_rev": "2b8375bc98bb9dc81c539c91aaea6adce12e1072",
   "usage_tag": "3.4.0",
@@ -276,7 +276,7 @@
   Var("dart_root") + "/third_party/pkg/dart2js_info":
       Var("dart_git") + "dart2js_info.git" + "@" + Var("dart2js_info_tag"),
   Var("dart_root") + "/third_party/pkg/dartdoc":
-      Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_tag"),
+      Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_rev"),
   Var("dart_root") + "/third_party/pkg/fixnum":
       Var("dart_git") + "fixnum.git" + "@" + Var("fixnum_tag"),
   Var("dart_root") + "/third_party/pkg/glob":
@@ -448,6 +448,16 @@
       "dep_type": "cipd",
   },
 
+  Var("dart_root") + "/pkg/front_end/test/fasta/types/benchmark_data": {
+    "packages": [
+      {
+        "package": "dart/cfe/benchmark_data",
+        "version": "sha1sum:4168b133ab7bce01c91311a8d4f25d4d6cb026f3",
+      }
+    ],
+    "dep_type": "cipd",
+  },
+
   # TODO(37531): Remove these cipd packages and build with sdk instead when
   # benchmark runner gets support for that.
   Var("dart_root") + "/benchmarks/FfiBoringssl/dart/native/out/": {
@@ -517,21 +527,6 @@
     ],
   },
   {
-    "name": "front_end_benchmark_data",
-    "pattern": ".",
-    "action": [
-      "download_from_google_storage",
-      "--no_auth",
-      "--no_resume",
-      "--bucket",
-      "dart-dependencies",
-      "--recursive",
-      "--extract",
-      "--directory",
-      Var('dart_root') + "/pkg/front_end/test/fasta/types",
-    ],
-  },
-  {
     # Pull Debian wheezy sysroot for i386 Linux
     'name': 'sysroot_i386',
     'pattern': '.',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 26354c4..7beb3f8 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -13,7 +13,10 @@
 import scm
 import subprocess
 import tempfile
+import platform
 
+def is_cpp_file(path):
+    return path.endswith('.cc') or path.endswith('.h')
 
 def _CheckFormat(input_api,
                  identification,
@@ -199,9 +202,6 @@
   """
 
     # Run only if .cc or .h file was modified.
-    def is_cpp_file(path):
-        return path.endswith('.cc') or path.endswith('.h')
-
     if all(not is_cpp_file(f.LocalPath()) for f in input_api.AffectedFiles()):
         return []
 
@@ -219,15 +219,47 @@
     else:
         return []
 
+def _CheckClangTidy(input_api, output_api):
+    """Run clang-tidy on VM changes."""
+
+    # Only run clang-tidy on linux x64.
+    if platform.system() != 'Linux' or platform.machine() != 'x86_64':
+        return []
+
+    # Run only for modified .cc or .h files.
+    files = []
+    for f in input_api.AffectedFiles():
+        path = f.LocalPath()
+        if is_cpp_file(path): files.append(path)
+
+    if not files:
+        return []
+
+    args = [
+        'tools/sdks/dart-sdk/bin/dart',
+        'runtime/tools/run_clang_tidy.dart',
+    ]
+    args.extend(files)
+    stdout = input_api.subprocess.check_output(args).strip()
+    if not stdout:
+        return []
+
+    return [
+        output_api.PresubmitError(
+            'The `clang-tidy` linter revealed issues:',
+            long_text=stdout)
+    ]
 
 def CheckChangeOnCommit(input_api, output_api):
     return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckBuildStatus(
         input_api, output_api) + _CheckDartFormat(input_api, output_api) +
             _CheckStatusFiles(input_api, output_api) + _CheckLayering(
+                input_api, output_api) + _CheckClangTidy(
                 input_api, output_api))
 
 
 def CheckChangeOnUpload(input_api, output_api):
     return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckDartFormat(
         input_api, output_api) + _CheckStatusFiles(input_api, output_api) +
-            _CheckLayering(input_api, output_api))
+            _CheckLayering(input_api, output_api) + _CheckClangTidy(
+                input_api, output_api))
diff --git a/benchmarks/Isolate/dart/Isolate.dart b/benchmarks/Isolate/dart/Isolate.dart
new file mode 100644
index 0000000..465d56a
--- /dev/null
+++ b/benchmarks/Isolate/dart/Isolate.dart
@@ -0,0 +1,186 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart'
+    show PrintEmitter, ScoreEmitter;
+import 'package:meta/meta.dart';
+
+class SendReceiveBytes extends AsyncBenchmarkBase {
+  SendReceiveBytes(String name,
+      {@required int this.size, @required bool this.useTransferable})
+      : super(name);
+
+  @override
+  Future<void> run() async {
+    await helper.run();
+  }
+
+  @override
+  Future<void> setup() async {
+    helper = SendReceiveHelper(size, useTransferable: useTransferable);
+    await helper.setup();
+  }
+
+  @override
+  Future<void> teardown() async {
+    await helper.finalize();
+  }
+
+  final bool useTransferable;
+  final int size;
+  SendReceiveHelper helper;
+}
+
+// Identical to BenchmarkBase from package:benchmark_harness but async.
+abstract class AsyncBenchmarkBase {
+  final String name;
+  final ScoreEmitter emitter;
+
+  Future<void> run();
+  Future<void> setup();
+  Future<void> teardown();
+
+  const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+  // Returns the number of microseconds per call.
+  Future<double> measureFor(int minimumMillis) async {
+    final minimumMicros = minimumMillis * 1000;
+    int iter = 0;
+    final watch = Stopwatch();
+    watch.start();
+    int elapsed = 0;
+    while (elapsed < minimumMicros) {
+      await run();
+      elapsed = watch.elapsedMicroseconds;
+      iter++;
+    }
+    return elapsed / iter;
+  }
+
+  // Measures the score for the benchmark and returns it.
+  Future<double> measure() async {
+    await setup();
+    await measureFor(500); // warm-up
+    final result = await measureFor(4000); // actual measurement
+    await teardown();
+    return result;
+  }
+
+  Future<void> report() async {
+    emitter.emit(name, await measure());
+  }
+}
+
+class StartMessage {
+  final SendPort sendPort;
+  final bool useTransferable;
+  final int size;
+
+  StartMessage(this.sendPort, this.useTransferable, this.size);
+}
+
+// Measures how long sending and receiving of [size]-length Uint8List takes.
+class SendReceiveHelper {
+  SendReceiveHelper(this.size, {@required bool this.useTransferable});
+
+  Future<void> setup() async {
+    data = new Uint8List(size);
+
+    port = ReceivePort();
+    inbox = StreamIterator<dynamic>(port);
+    workerCompleted = Completer<bool>();
+    workerExitedPort = ReceivePort()
+      ..listen((_) => workerCompleted.complete(true));
+    worker = await Isolate.spawn(
+        isolate, StartMessage(port.sendPort, useTransferable, size),
+        onExit: workerExitedPort.sendPort);
+    await inbox.moveNext();
+    outbox = inbox.current;
+  }
+
+  Future<void> finalize() async {
+    outbox.send(null);
+    await workerCompleted.future;
+    workerExitedPort.close();
+    port.close();
+  }
+
+  // Send data to worker, wait for an answer.
+  Future<void> run() async {
+    outbox.send(packageList(data, useTransferable));
+    await inbox.moveNext();
+    final received = inbox.current;
+    if (useTransferable) {
+      final TransferableTypedData transferable = received;
+      transferable.materialize();
+    }
+  }
+
+  Uint8List data;
+  ReceivePort port;
+  StreamIterator<dynamic> inbox;
+  SendPort outbox;
+  Isolate worker;
+  Completer<bool> workerCompleted;
+  ReceivePort workerExitedPort;
+  final int size;
+  final bool useTransferable;
+}
+
+packageList(Uint8List data, bool useTransferable) =>
+    useTransferable ? TransferableTypedData.fromList(<Uint8List>[data]) : data;
+
+Future<void> isolate(StartMessage startMessage) async {
+  final port = ReceivePort();
+  final inbox = StreamIterator<dynamic>(port);
+  final data = Uint8List.view(new Uint8List(startMessage.size).buffer);
+
+  startMessage.sendPort.send(port.sendPort);
+  while (true) {
+    await inbox.moveNext();
+    final received = inbox.current;
+    if (received == null) {
+      break;
+    }
+    if (startMessage.useTransferable) {
+      final TransferableTypedData transferable = received;
+      transferable.materialize();
+    }
+    startMessage.sendPort.send(packageList(data, startMessage.useTransferable));
+  }
+  port.close();
+}
+
+class SizeName {
+  const SizeName(this.size, this.name);
+
+  final int size;
+  final String name;
+}
+
+final List<SizeName> sizes = <SizeName>[
+  SizeName(1 * 1024, "1KB"),
+  SizeName(10 * 1024, "10KB"),
+  SizeName(100 * 1024, "100KB"),
+  SizeName(1 * 1024 * 1024, "1MB"),
+  SizeName(10 * 1024 * 1024, "10MB"),
+  SizeName(100 * 1024 * 1024, "100MB")
+];
+
+Future<void> main() async {
+  for (SizeName sizeName in sizes) {
+    await SendReceiveBytes("Isolate.SendReceiveBytes${sizeName.name}",
+            size: sizeName.size, useTransferable: false)
+        .report();
+    await SendReceiveBytes(
+            "Isolate.SendReceiveBytesTransferable${sizeName.name}",
+            size: sizeName.size,
+            useTransferable: true)
+        .report();
+  }
+}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index f073da1..d205e966 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -247,8 +247,6 @@
   # Linux-specific compiler flags setup.
   # ------------------------------------
   if (is_linux) {
-    cflags += [ "-pthread" ]
-    ldflags += [ "-pthread" ]
     if (is_clang) {
       if (current_cpu == "arm") {
         cflags += [ "--target=armv7-linux-gnueabihf" ]
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 62f7524..0db95b7 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -5,9 +5,26 @@
 import("//build/config/sysroot.gni")
 
 config("sdk") {
+  # Don't allow visible symbols from libc++ to be re-exported.
+  ldflags = [
+    "-nodefaultlibs",
+    "-lc++",
+    "-lc",
+    "-lm",
+    "-lclang_rt.builtins",
+    "-Wl,--exclude-libs=libc++.a",
+  ]
+
+  if (is_asan) {
+    ldflags += [
+      "-lpthread",
+      "-lrt",
+    ]
+  }
+
   if (sysroot != "") {
     cflags = [ "--sysroot=" + sysroot ]
-    ldflags = [ "--sysroot=" + sysroot ]
+    ldflags += [ "--sysroot=" + sysroot ]
 
     # Need to get some linker flags out of the sysroot.
     ldflags += [ exec_script("sysroot_ld_path.py",
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index c65ccb2..5bf0c26 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  1.27.2
+  1.27.3
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -373,6 +373,7 @@
   
   
   
+  
 <h3>Requests</h3><dl><dt class="request"><a name="request_server.getVersion">server.getVersion</a></dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "server.getVersion"
@@ -3007,6 +3008,8 @@
   
   
   
+  
+  
 <dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
     <p>
       A directive to begin overlaying the contents of a file. The supplied
@@ -5500,7 +5503,7 @@
       An enumeration of the services provided by the server domain.
     </p>
     
-  <dl><dt class="value">STATUS</dt></dl></dd><dt class="typeDefinition"><a name="type_SourceChange">SourceChange: object</a></dt><dd>
+  <dl><dt class="value">LOG</dt><dt class="value">STATUS</dt></dl></dd><dt class="typeDefinition"><a name="type_SourceChange">SourceChange: object</a></dt><dd>
     <p>
       A description of a set of edits that implement a single conceptual change.
     </p>
@@ -5996,7 +5999,7 @@
   TODO: TBD
 </p>
 <h2 class="domain"><a name="index">Index</a></h2>
-<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
 
 
 </body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index f51b81c..686011c 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.27.2';
+const String PROTOCOL_VERSION = '1.27.3';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -341,6 +341,8 @@
 const String SERVER_NOTIFICATION_ERROR_IS_FATAL = 'isFatal';
 const String SERVER_NOTIFICATION_ERROR_MESSAGE = 'message';
 const String SERVER_NOTIFICATION_ERROR_STACK_TRACE = 'stackTrace';
+const String SERVER_NOTIFICATION_LOG = 'server.log';
+const String SERVER_NOTIFICATION_LOG_ENTRY = 'entry';
 const String SERVER_NOTIFICATION_STATUS = 'server.status';
 const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
 const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index b00966b..46ed75f 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -22728,21 +22728,330 @@
 }
 
 /**
+ * ServerLogEntry
+ *
+ * {
+ *   "time": int
+ *   "kind": ServerLogEntryKind
+ *   "data": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntry implements HasToJson {
+  int _time;
+
+  ServerLogEntryKind _kind;
+
+  String _data;
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log
+   * entry.
+   */
+  int get time => _time;
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log
+   * entry.
+   */
+  void set time(int value) {
+    assert(value != null);
+    this._time = value;
+  }
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data"
+   * field.
+   */
+  ServerLogEntryKind get kind => _kind;
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data"
+   * field.
+   */
+  void set kind(ServerLogEntryKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind"
+   * field.
+   */
+  String get data => _data;
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind"
+   * field.
+   */
+  void set data(String value) {
+    assert(value != null);
+    this._data = value;
+  }
+
+  ServerLogEntry(int time, ServerLogEntryKind kind, String data) {
+    this.time = time;
+    this.kind = kind;
+    this.data = data;
+  }
+
+  factory ServerLogEntry.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int time;
+      if (json.containsKey("time")) {
+        time = jsonDecoder.decodeInt(jsonPath + ".time", json["time"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "time");
+      }
+      ServerLogEntryKind kind;
+      if (json.containsKey("kind")) {
+        kind = new ServerLogEntryKind.fromJson(
+            jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      String data;
+      if (json.containsKey("data")) {
+        data = jsonDecoder.decodeString(jsonPath + ".data", json["data"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "data");
+      }
+      return new ServerLogEntry(time, kind, data);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "ServerLogEntry", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["time"] = time;
+    result["kind"] = kind.toJson();
+    result["data"] = data;
+    return result;
+  }
+
+  @override
+  String toString() => json.encode(toJson());
+
+  @override
+  bool operator ==(other) {
+    if (other is ServerLogEntry) {
+      return time == other.time && kind == other.kind && data == other.data;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, time.hashCode);
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, data.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ *   NOTIFICATION
+ *   RAW
+ *   REQUEST
+ *   RESPONSE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntryKind implements Enum {
+  /**
+   * A notification from the server, such as "analysis.highlights". The "data"
+   * field contains a JSON object with abbreviated notification.
+   */
+  static const ServerLogEntryKind NOTIFICATION =
+      const ServerLogEntryKind._("NOTIFICATION");
+
+  /**
+   * Arbitrary string, describing some event that happened in the server, e.g.
+   * starting a file analysis, and details which files were accessed. These
+   * entries are not structured, but provide context information about requests
+   * and notification, and can be related by "time" for further manual
+   * analysis.
+   */
+  static const ServerLogEntryKind RAW = const ServerLogEntryKind._("RAW");
+
+  /**
+   * A request from the client, as the server views it, e.g. "edit.getAssists".
+   * The "data" field contains a JSON object with abbreviated request.
+   */
+  static const ServerLogEntryKind REQUEST =
+      const ServerLogEntryKind._("REQUEST");
+
+  /**
+   * Various counters and measurements related to execution of a request. The
+   * "data" field contains a JSON object with following fields:
+   *
+   * - "id" - the id of the request - copied from the request.
+   * - "method" - the method of the request, e.g. "edit.getAssists".
+   * - "clientRequestTime" - the time (milliseconds since epoch) at which the
+   *   client made the request - copied from the request.
+   * - "serverRequestTime" - the time (milliseconds since epoch) at which the
+   *   server received and decoded the JSON request.
+   * - "responseTime" - the time (milliseconds since epoch) at which the server
+   *   created the response to be encoded into JSON and sent to the client.
+   */
+  static const ServerLogEntryKind RESPONSE =
+      const ServerLogEntryKind._("RESPONSE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<ServerLogEntryKind> VALUES = const <ServerLogEntryKind>[
+    NOTIFICATION,
+    RAW,
+    REQUEST,
+    RESPONSE
+  ];
+
+  @override
+  final String name;
+
+  const ServerLogEntryKind._(this.name);
+
+  factory ServerLogEntryKind(String name) {
+    switch (name) {
+      case "NOTIFICATION":
+        return NOTIFICATION;
+      case "RAW":
+        return RAW;
+      case "REQUEST":
+        return REQUEST;
+      case "RESPONSE":
+        return RESPONSE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory ServerLogEntryKind.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new ServerLogEntryKind(json);
+      } catch (_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "ServerLogEntryKind", json);
+  }
+
+  @override
+  String toString() => "ServerLogEntryKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * server.log params
+ *
+ * {
+ *   "entry": ServerLogEntry
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogParams implements HasToJson {
+  ServerLogEntry _entry;
+
+  ServerLogEntry get entry => _entry;
+
+  void set entry(ServerLogEntry value) {
+    assert(value != null);
+    this._entry = value;
+  }
+
+  ServerLogParams(ServerLogEntry entry) {
+    this.entry = entry;
+  }
+
+  factory ServerLogParams.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      ServerLogEntry entry;
+      if (json.containsKey("entry")) {
+        entry = new ServerLogEntry.fromJson(
+            jsonDecoder, jsonPath + ".entry", json["entry"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "entry");
+      }
+      return new ServerLogParams(entry);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "server.log params", json);
+    }
+  }
+
+  factory ServerLogParams.fromNotification(Notification notification) {
+    return new ServerLogParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["entry"] = entry.toJson();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("server.log", toJson());
+  }
+
+  @override
+  String toString() => json.encode(toJson());
+
+  @override
+  bool operator ==(other) {
+    if (other is ServerLogParams) {
+      return entry == other.entry;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, entry.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
  * ServerService
  *
  * enum {
+ *   LOG
  *   STATUS
  * }
  *
  * Clients may not extend, implement or mix-in this class.
  */
 class ServerService implements Enum {
+  static const ServerService LOG = const ServerService._("LOG");
+
   static const ServerService STATUS = const ServerService._("STATUS");
 
   /**
    * A list containing all of the enum values that are defined.
    */
-  static const List<ServerService> VALUES = const <ServerService>[STATUS];
+  static const List<ServerService> VALUES = const <ServerService>[LOG, STATUS];
 
   @override
   final String name;
@@ -22751,6 +23060,8 @@
 
   factory ServerService(String name) {
     switch (name) {
+      case "LOG":
+        return LOG;
       case "STATUS":
         return STATUS;
     }
@@ -23071,6 +23382,7 @@
  *   "lexeme": String
  *   "type": optional String
  *   "validElementKinds": optional List<String>
+ *   "offset": int
  * }
  *
  * Clients may not extend, implement or mix-in this class.
@@ -23082,6 +23394,8 @@
 
   List<String> _validElementKinds;
 
+  int _offset;
+
   /**
    * The token's lexeme.
    */
@@ -23127,10 +23441,27 @@
     this._validElementKinds = value;
   }
 
-  TokenDetails(String lexeme, {String type, List<String> validElementKinds}) {
+  /**
+   * The offset of the first character of the token in the file which it
+   * originated from.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the first character of the token in the file which it
+   * originated from.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  TokenDetails(String lexeme, int offset,
+      {String type, List<String> validElementKinds}) {
     this.lexeme = lexeme;
     this.type = type;
     this.validElementKinds = validElementKinds;
+    this.offset = offset;
   }
 
   factory TokenDetails.fromJson(
@@ -23156,7 +23487,13 @@
             json["validElementKinds"],
             jsonDecoder.decodeString);
       }
-      return new TokenDetails(lexeme,
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      return new TokenDetails(lexeme, offset,
           type: type, validElementKinds: validElementKinds);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "TokenDetails", json);
@@ -23173,6 +23510,7 @@
     if (validElementKinds != null) {
       result["validElementKinds"] = validElementKinds;
     }
+    result["offset"] = offset;
     return result;
   }
 
@@ -23185,7 +23523,8 @@
       return lexeme == other.lexeme &&
           type == other.type &&
           listEqual(validElementKinds, other.validElementKinds,
-              (String a, String b) => a == b);
+              (String a, String b) => a == b) &&
+          offset == other.offset;
     }
     return false;
   }
@@ -23196,6 +23535,7 @@
     hash = JenkinsSmiHash.combine(hash, lexeme.hashCode);
     hash = JenkinsSmiHash.combine(hash, type.hashCode);
     hash = JenkinsSmiHash.combine(hash, validElementKinds.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
     return JenkinsSmiHash.finish(hash);
   }
 }
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index bd6fa83..1949461 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -49,6 +49,7 @@
 import 'package:analysis_server/src/utilities/file_string_sink.dart';
 import 'package:analysis_server/src/utilities/null_string_sink.dart';
 import 'package:analysis_server/src/utilities/request_statistics.dart';
+import 'package:analysis_server/src/utilities/tee_string_sink.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/exception/exception.dart';
@@ -204,9 +205,11 @@
         } else if (name.startsWith('file:')) {
           String path = name.substring('file:'.length);
           sink = FileStringSink(path);
-          requestStatistics?.sink = sink;
         }
       }
+      if (requestStatistics != null) {
+        sink = TeeStringSink(sink, requestStatistics.perfLoggerStringSink);
+      }
       _analysisPerformanceLogger = new PerformanceLog(sink);
     }
 
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index 72f127d..4f8f13a 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -93,7 +93,9 @@
   ByteStreamServerChannel(
       this._input, this._output, this._instrumentationService,
       {RequestStatisticsHelper requestStatistics})
-      : _requestStatistics = requestStatistics;
+      : _requestStatistics = requestStatistics {
+    _requestStatistics?.serverChannel = this;
+  }
 
   /**
    * Future that will be completed when the input stream is closed.
@@ -132,8 +134,10 @@
     ServerPerformanceStatistics.serverChannel.makeCurrentWhile(() {
       String jsonEncoding = json.encode(notification.toJson());
       _outputLine(jsonEncoding);
-      _instrumentationService.logNotification(jsonEncoding);
-      _requestStatistics?.logNotification(notification);
+      if (!identical(notification.event, 'server.log')) {
+        _instrumentationService.logNotification(jsonEncoding);
+        _requestStatistics?.logNotification(notification);
+      }
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index 7b4eee3..c3a610b 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -425,10 +424,8 @@
   }
 
   static bool _isDynamicExpression(Expression e) {
-    if (e is SimpleIdentifier && e.staticElement is PrefixElement) {
-      return false;
-    }
-    return resolutionMap.staticTypeForExpression(e).isDynamic;
+    var type = e.staticType;
+    return type != null && type.isDynamic;
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index c7d5f28..5c60f3b 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -59,6 +59,10 @@
         new ServerSetSubscriptionsParams.fromRequest(request)
             .subscriptions
             .toSet();
+
+    server.requestStatistics?.isNotificationSubscribed =
+        server.serverServices.contains(ServerService.LOG);
+
     return new ServerSetSubscriptionsResult().toResponse(request.id);
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
index 3de909c..2df189b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
@@ -14,6 +14,7 @@
 import 'package:analysis_server/src/protocol_server.dart' show Outline;
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' show ElementKind;
 
 // If the client does not provide capabilities.documentSymbol.symbolKind.valueSet
 // then we must never send a kind that's not in this list.
@@ -77,8 +78,13 @@
     LineInfo lineInfo,
     Outline outline,
   ) {
+    final name = outline.element.name != null && outline.element.name != ""
+        ? outline.element.name
+        : (outline.element.kind == ElementKind.EXTENSION
+            ? "<unnamed extension>"
+            : "<unnamed>");
     return new DocumentSymbol(
-      outline.element.name,
+      name,
       outline.element.parameters,
       elementKindToSymbolKind(clientSupportedSymbolKinds, outline.element.kind),
       outline.element.isDeprecated,
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 8088f62..eea32fe 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -313,6 +313,8 @@
       case server.ElementKind.ENUM:
       case server.ElementKind.ENUM_CONSTANT:
         return const [lsp.SymbolKind.Enum];
+      case server.ElementKind.EXTENSION:
+        return const [lsp.SymbolKind.Namespace];
       case server.ElementKind.FIELD:
         return const [lsp.SymbolKind.Field];
       case server.ElementKind.FILE:
@@ -357,7 +359,10 @@
     }
   }
 
-  return getKindPreferences().firstWhere(isSupported, orElse: () => null);
+  // LSP requires we specify *some* kind, so in the case where the above code doesn't
+  // match we'll just have to send a value to avoid a crash.
+  return getKindPreferences()
+      .firstWhere(isSupported, orElse: () => lsp.SymbolKind.Obj);
 }
 
 String getCompletionDetail(
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index eb35df8..f6febdc 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -310,14 +310,6 @@
   static const String TRAIN_USING = "train-using";
 
   /**
-   * The name of the flag to include into the analysis driver log all
-   * communications with the client - requests, responses, shortened
-   * notifications.
-   */
-  static const String INCLUDE_PROTOCOL_TO_DRIVER_LOG =
-      "include-protocol-to-driver-log";
-
-  /**
    * The instrumentation server that is to be used by the analysis server.
    */
   InstrumentationServer instrumentationServer;
@@ -475,11 +467,6 @@
       }
     }
 
-    RequestStatisticsHelper requestStatisticsHelper;
-    if (results[INCLUDE_PROTOCOL_TO_DRIVER_LOG] == true) {
-      requestStatisticsHelper = RequestStatisticsHelper();
-    }
-
     CompilerContext.runWithDefaultOptions((_) async {
       if (analysisServerOptions.useLanguageServerProtocol) {
         startLspServer(results, analysisServerOptions, dartSdkManager,
@@ -491,7 +478,7 @@
             parser,
             dartSdkManager,
             instrumentationService,
-            requestStatisticsHelper,
+            RequestStatisticsHelper(),
             analytics,
             diagnosticServerPort);
       }
@@ -810,9 +797,6 @@
     parser.addOption(TRAIN_USING,
         help: "Pass in a directory to analyze for purposes of training an "
             "analysis server snapshot.");
-    parser.addFlag(INCLUDE_PROTOCOL_TO_DRIVER_LOG,
-        defaultsTo: false,
-        help: "Whether to use include protocol into the driver log");
 
     return parser;
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 27b6639..9e1113b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -269,6 +269,18 @@
         }
       }
     }
+
+    if (containingNode is VariableDeclaration &&
+        containingNode.equals != null &&
+        target.offset >= containingNode.equals.end) {
+      var parent = containingNode.parent;
+      if (parent is VariableDeclarationList) {
+        var type = parent.type?.type;
+        if (type is InterfaceType) {
+          addTypeTag(type);
+        }
+      }
+    }
   }
 
   static List<String> _ensureList(Map<String, List<String>> map, String key) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
index b552cf6..318736e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
@@ -116,7 +116,7 @@
 
 bool testInsideQuotes(DartCompletionRequest request) {
   final token = getCurrentToken(request);
-  if (token.isSynthetic) {
+  if (token == null || token.isSynthetic) {
     return false;
   }
 
@@ -136,7 +136,7 @@
 }
 
 bool isTokenDot(Token token) {
-  return !token.isSynthetic && token.lexeme.endsWith('.');
+  return token != null && !token.isSynthetic && token.lexeme.endsWith('.');
 }
 
 bool testFollowingDot(DartCompletionRequest request) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index ab489ad..f2815f2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -41,8 +41,10 @@
       if (elem is ClassElement) {
         // Suggestions provided by StaticMemberContributor
         return const <CompletionSuggestion>[];
-      }
-      if (elem is PrefixElement) {
+      } else if (elem is ExtensionElement) {
+        // Suggestions provided by StaticMemberContributor
+        return const <CompletionSuggestion>[];
+      } else if (elem is PrefixElement) {
         // Suggestions provided by LibraryMemberContributor
         return const <CompletionSuggestion>[];
       }
@@ -52,6 +54,13 @@
       _addInstanceMembers(expression.staticElement);
     } else {
       var type = expression.staticType;
+      if (type == null) {
+        // Without a type we cannot find the extensions that apply.
+        // We shouldn't get to this point, but there's an NPE if we invoke
+        // `_resolveExtendedType` when `type` is `null`, so we guard against it
+        // to ensure that we can return the suggestions from other providers.
+        return const <CompletionSuggestion>[];
+      }
       LibraryScope nameScope = new LibraryScope(containingLibrary);
       for (var extension in nameScope.extensions) {
         var typeSystem = containingLibrary.context.typeSystem;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
index 2afa953..897f2c2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
@@ -8,7 +8,6 @@
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
 import 'package:analysis_server/src/utilities/flutter.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
@@ -67,11 +66,9 @@
     }
     containingLibrary = request.libraryElement;
     if (classDecl is ClassDeclaration) {
-      return _computeSuggestionsForClass2(
-          resolutionMap.elementDeclaredByClassDeclaration(classDecl), request);
+      return _computeSuggestionsForClass2(classDecl.declaredElement, request);
     } else if (classDecl is MixinDeclaration) {
-      return _computeSuggestionsForClass2(
-          resolutionMap.elementDeclaredByMixinDeclaration(classDecl), request);
+      return _computeSuggestionsForClass2(classDecl.declaredElement, request);
     }
     return const <CompletionSuggestion>[];
   }
@@ -109,17 +106,11 @@
   }
 
   List<CompletionSuggestion> _computeSuggestionsForClass2(
-      ClassElement classElement, DartCompletionRequest request,
-      {bool skipChildClass = true}) {
+      ClassElement classElement, DartCompletionRequest request) {
     bool isFunctionalArgument = request.target.isFunctionalArgument();
     kind = isFunctionalArgument
         ? CompletionSuggestionKind.IDENTIFIER
         : CompletionSuggestionKind.INVOCATION;
-    if (!skipChildClass) {
-      _addSuggestionsForType(classElement.type, request,
-          isFunctionalArgument: isFunctionalArgument);
-    }
-
     for (InterfaceType type in classElement.allSupertypes) {
       _addSuggestionsForType(type, request,
           isFunctionalArgument: isFunctionalArgument);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 4ef2e9f..d3300ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -647,6 +647,12 @@
   }
 
   @override
+  visitSwitchCase(SwitchCase node) {
+    _addStatementKeywords(node);
+    return super.visitSwitchCase(node);
+  }
+
+  @override
   visitTryStatement(TryStatement node) {
     var obj = entity;
     if (obj is CatchClause ||
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index 9e548cc..3e3cf86 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -12,7 +12,6 @@
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
 import 'package:analysis_server/src/services/completion/dart/utilities.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol
     show Element, ElementKind;
@@ -112,8 +111,7 @@
       ClassDeclaration classDecl, ConstructorDeclaration constructorDecl) {
     String completion = classDecl.name.name;
 
-    ClassElement classElement =
-        resolutionMap.elementDeclaredByClassDeclaration(classDecl);
+    ClassElement classElement = classDecl.declaredElement;
     int relevance = optype.returnValueSuggestionsFilter(
         classElement?.type, DART_RELEVANCE_DEFAULT);
     if (constructorDecl != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index c058170..f5b9ff3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -12,7 +12,6 @@
 import 'package:analysis_server/src/services/completion/dart/utilities.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -444,8 +443,7 @@
       {bool isAbstract = false,
       bool isDeprecated = false,
       int relevance = DART_RELEVANCE_DEFAULT}) {
-    ClassElement classElement =
-        resolutionMap.elementDeclaredByEnumDeclaration(enumDeclaration);
+    ClassElement classElement = enumDeclaration.declaredElement;
     relevance =
         optype.returnValueSuggestionsFilter(classElement?.type, relevance);
     if (relevance != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index 26a7ce5..bef2ef6 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -25,7 +25,7 @@
     Expression targetId = request.dotTarget;
     if (targetId is Identifier && !request.target.isCascade) {
       Element elem = targetId.staticElement;
-      if (elem is ClassElement) {
+      if (elem is ClassElement || elem is ExtensionElement) {
         LibraryElement containingLibrary = request.libraryElement;
         // Gracefully degrade if the library could not be determined
         // e.g. detached part file or source change
@@ -75,6 +75,11 @@
   }
 
   @override
+  visitExtensionElement(ExtensionElement element) {
+    element.visitChildren(this);
+  }
+
+  @override
   visitFieldElement(FieldElement element) {
     if (element.isStatic) {
       _addSuggestion(element);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 327aca1..1c90f7b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -215,6 +215,13 @@
   }
 
   @override
+  visitExtensionElement(ExtensionElement element) {
+    if (!instCreation) {
+      addSuggestion(element);
+    }
+  }
+
+  @override
   visitFunctionElement(FunctionElement element) {
     if (!typesOnly) {
       int relevance = element.library == containingLibrary
diff --git a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
index 3d225b5..fbde099 100644
--- a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
@@ -54,8 +54,8 @@
 
   /// Create the details for a single [token], using the given list of [kinds].
   void _createDetails(Token token, String type, List<String> kinds) {
-    details.add(
-        new TokenDetails(token.lexeme, type: type, validElementKinds: kinds));
+    details.add(new TokenDetails(token.lexeme, token.offset,
+        type: type, validElementKinds: kinds));
   }
 
   /// Return a unique identifier for the type of the given [expression].
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 52641ae..9cb8c62 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -32,11 +32,7 @@
  */
 class DartAssistKind {
   static const ADD_TYPE_ANNOTATION = const AssistKind(
-      'dart.assist.addTypeAnnotation', 30, "Add type annotation",
-      associatedErrorCodes: <String>[
-        'always_specify_types',
-        'type_annotate_public_apis'
-      ]);
+      'dart.assist.addTypeAnnotation', 30, "Add type annotation");
   static const ASSIGN_TO_LOCAL_VARIABLE = const AssistKind(
       'dart.assist.assignToVariable', 30, "Assign value to new local variable");
   static const CONVERT_CLASS_TO_MIXIN = const AssistKind(
@@ -48,18 +44,15 @@
   static const CONVERT_DOCUMENTATION_INTO_LINE = const AssistKind(
       'dart.assist.convert.lineComment',
       30,
-      "Convert to line documentation comment",
-      associatedErrorCodes: <String>['slash_for_doc_comments']);
+      "Convert to line documentation comment");
   static const CONVERT_INTO_ASYNC_BODY = const AssistKind(
       'dart.assist.convert.bodyToAsync', 29, "Convert to async function body");
   static const CONVERT_INTO_BLOCK_BODY = const AssistKind(
       'dart.assist.convert.bodyToBlock', 30, "Convert to block body");
   static const CONVERT_INTO_EXPRESSION_BODY = const AssistKind(
-      'dart.assist.convert.bodyToExpression', 30, "Convert to expression body",
-      associatedErrorCodes: <String>['prefer_expression_function_bodies']);
+      'dart.assist.convert.bodyToExpression', 30, "Convert to expression body");
   static const CONVERT_INTO_FINAL_FIELD = const AssistKind(
-      'dart.assist.convert.getterToFinalField', 30, "Convert to final field",
-      associatedErrorCodes: <String>['prefer_final_fields']);
+      'dart.assist.convert.getterToFinalField', 30, "Convert to final field");
   static const CONVERT_INTO_FOR_INDEX = const AssistKind(
       'dart.assist.convert.forEachToForIndex', 30, "Convert to for-index loop");
   static const CONVERT_INTO_GENERIC_FUNCTION_SYNTAX = const AssistKind(
@@ -72,6 +65,7 @@
       const AssistKind('dart.assist.convert.isNot', 30, "Convert to is!");
   static const CONVERT_INTO_IS_NOT_EMPTY = const AssistKind(
       'dart.assist.convert.isNotEmpty', 30, "Convert to 'isNotEmpty'",
+      // todo (pq): unify w/ fix
       associatedErrorCodes: <String>['prefer_is_not_empty']);
   static const CONVERT_PART_OF_TO_URI = const AssistKind(
       'dart.assist.convert.partOfToPartUri', 30, "Convert to use a URI");
@@ -84,18 +78,11 @@
       30,
       "Convert to field formal parameter");
   static const CONVERT_TO_FOR_ELEMENT = const AssistKind(
-      'dart.assist.convertToForElement', 30, "Convert to a 'for' element",
-      associatedErrorCodes: <String>[
-        'prefer_for_elements_to_map_fromIterable'
-      ]);
+      'dart.assist.convertToForElement', 30, "Convert to a 'for' element");
   static const CONVERT_TO_IF_ELEMENT = const AssistKind(
-      'dart.assist.convertToIfElement', 30, "Convert to an 'if' element",
-      associatedErrorCodes: <String>[
-        'prefer_if_elements_to_conditional_expressions'
-      ]);
+      'dart.assist.convertToIfElement', 30, "Convert to an 'if' element");
   static const CONVERT_TO_INT_LITERAL = const AssistKind(
-      'dart.assist.convert.toIntLiteral', 30, "Convert to an int literal",
-      associatedErrorCodes: <String>['prefer_int_literals']);
+      'dart.assist.convert.toIntLiteral', 30, "Convert to an int literal");
   static const CONVERT_TO_LIST_LITERAL = const AssistKind(
       'dart.assist.convert.toListLiteral', 30, "Convert to list literal",
       // todo (brianwilkerson): unify w/ fix
@@ -113,12 +100,12 @@
       30,
       "Convert to normal parameter");
   static const CONVERT_TO_NULL_AWARE = const AssistKind(
-      'dart.assist.convert.toNullAware', 30, "Convert to use '?.'",
-      associatedErrorCodes: <String>['prefer_null_aware_operators']);
+      'dart.assist.convert.toNullAware', 30, "Convert to use '?.'");
   static const CONVERT_TO_PACKAGE_IMPORT = const AssistKind(
       'dart.assist.convert.relativeToPackageImport',
       30,
       "Convert to 'package:' import",
+      // todo (pq): migrate to (conditional) fix
       associatedErrorCodes: <String>['avoid_relative_lib_imports']);
   static const CONVERT_TO_SET_LITERAL = const AssistKind(
       'dart.assist.convert.toSetLiteral', 30, "Convert to set literal",
@@ -128,10 +115,12 @@
       'dart.assist.convert.toSingleQuotedString',
       30,
       "Convert to single quoted string",
+      // todo (pq): migrate to (conditional) fix
       associatedErrorCodes: <String>['prefer_single_quotes']);
-  static const CONVERT_TO_SPREAD = const AssistKind(
-      'dart.assist.convertToSpread', 30, "Convert to a spread",
-      associatedErrorCodes: <String>['prefer_spread_collections']);
+  static const CONVERT_TO_SPREAD =
+      const AssistKind('dart.assist.convertToSpread', 30, "Convert to a spread",
+          // todo (pq): migrate to (conditional) fix
+          associatedErrorCodes: <String>['prefer_spread_collections']);
   static const ENCAPSULATE_FIELD =
       const AssistKind('dart.assist.encapsulateField', 30, "Encapsulate field");
   static const EXCHANGE_OPERANDS =
@@ -172,9 +161,10 @@
       'dart.assist.flutter.wrap.streamBuilder', 30, "Wrap with StreamBuilder");
   static const IMPORT_ADD_SHOW = const AssistKind(
       'dart.assist.addShowCombinator', 30, "Add explicit 'show' combinator");
-  static const INLINE_INVOCATION = const AssistKind(
-      'dart.assist.inline', 30, "Inline invocation of '{0}'",
-      associatedErrorCodes: <String>['prefer_inlined_adds']);
+  static const INLINE_INVOCATION =
+      const AssistKind('dart.assist.inline', 30, "Inline invocation of '{0}'",
+          // todo (pq): migrate to (conditional) fix
+          associatedErrorCodes: <String>['prefer_inlined_adds']);
   static const INTRODUCE_LOCAL_CAST_TYPE = const AssistKind(
       'dart.assist.introduceLocalCast',
       30,
@@ -193,6 +183,7 @@
       'dart.assist.joinVariableDeclaration', 30, "Join variable declaration");
   static const REMOVE_TYPE_ANNOTATION = const AssistKind(
       'dart.assist.removeTypeAnnotation', 29, "Remove type annotation",
+      // todo (pq): migrate to (conditional) fix
       associatedErrorCodes: <String>[
         'avoid_return_types_on_setters',
         'type_init_formals'
@@ -209,6 +200,7 @@
       'dart.assist.sort.child.properties.last',
       30,
       "Move child property to end of arguments",
+      // todo (pq): migrate to (conditional) fix
       associatedErrorCodes: <String>[
         'sort_child_properties_last',
       ]);
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 9dc704e..f3ba612 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -8,26 +8,22 @@
 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
 import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/base_processor.dart';
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
 import 'package:analysis_server/src/services/correction/selection_analyzer.dart';
 import 'package:analysis_server/src/services/correction/statement_analyzer.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
-import 'package:analysis_server/src/utilities/flutter.dart';
-import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/precedence.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/dart/analysis/session_helper.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
@@ -36,67 +32,42 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 import 'package:meta/meta.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' hide context;
 
 typedef _SimpleIdentifierVisitor(SimpleIdentifier node);
 
 /**
  * The computer for Dart assists.
  */
-class AssistProcessor {
+class AssistProcessor extends BaseProcessor {
   final DartAssistContext context;
-  final int selectionOffset;
-  final int selectionLength;
-  final int selectionEnd;
-
-  final AnalysisSession session;
-  final AnalysisSessionHelper sessionHelper;
-  final TypeProvider typeProvider;
-  final String file;
-  final CorrectionUtils utils;
-  final Flutter flutter;
-
   final List<Assist> assists = <Assist>[];
 
-  AstNode node;
-
   AssistProcessor(this.context)
-      : selectionOffset = context.selectionOffset,
-        selectionLength = context.selectionLength,
-        selectionEnd = context.selectionOffset + context.selectionLength,
-        session = context.resolveResult.session,
-        sessionHelper = AnalysisSessionHelper(context.resolveResult.session),
-        typeProvider = context.resolveResult.typeProvider,
-        file = context.resolveResult.path,
-        utils = new CorrectionUtils(context.resolveResult),
-        flutter = Flutter.of(context.resolveResult);
-
-  /**
-   * Returns the EOL to use for this [CompilationUnit].
-   */
-  String get eol => utils.endOfLine;
-
-  /**
-   * Return the status of the known experiments.
-   */
-  ExperimentStatus get experimentStatus =>
-      (session.analysisContext.analysisOptions as AnalysisOptionsImpl)
-          .experimentStatus;
+      : super(
+          selectionOffset: context.selectionOffset,
+          selectionLength: context.selectionLength,
+          resolvedResult: context.resolveResult,
+          workspace: context.workspace,
+        );
 
   Future<List<Assist>> compute() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    if (!_setupCompute()) {
+    if (!setupCompute()) {
       return assists;
     }
-
-    await _addProposal_addTypeAnnotation_DeclaredIdentifier();
-    await _addProposal_addTypeAnnotation_SimpleFormalParameter();
-    await _addProposal_addTypeAnnotation_VariableDeclaration();
+    if (!_containsErrorCode(
+      {LintNames.always_specify_types, LintNames.type_annotate_public_apis},
+    )) {
+      await _addProposals_addTypeAnnotation();
+    }
     await _addProposal_assignToLocalVariable();
     await _addProposal_convertClassToMixin();
     await _addProposal_convertDocumentationIntoBlock();
-    await _addProposal_convertDocumentationIntoLine();
+    if (!_containsErrorCode(
+      {LintNames.slash_for_doc_comments},
+    )) {
+      await _addProposal_convertDocumentationIntoLine();
+    }
     await _addProposal_convertIntoFinalField();
     await _addProposal_convertIntoGetter();
     await _addProposal_convertListConstructorToListLiteral();
@@ -107,17 +78,29 @@
     await _addProposal_convertToAsyncFunctionBody();
     await _addProposal_convertToBlockFunctionBody();
     await _addProposal_convertToDoubleQuotedString();
-    await _addProposal_convertToExpressionFunctionBody();
+    if (!_containsErrorCode(
+      {LintNames.prefer_expression_function_bodies},
+    )) {
+      await _addProposal_convertToExpressionFunctionBody();
+    }
     await _addProposal_convertToFieldParameter();
     await _addProposal_convertToForIndexLoop();
     await _addProposal_convertToGenericFunctionSyntax();
-    await _addProposal_convertToIntLiteral();
+    if (!_containsErrorCode(
+      {LintNames.prefer_int_literals},
+    )) {
+      await _addProposal_convertToIntLiteral();
+    }
     await _addProposal_convertToIsNot_onIs();
     await _addProposal_convertToIsNot_onNot();
     await _addProposal_convertToIsNotEmpty();
     await _addProposal_convertToMultilineString();
     await _addProposal_convertToNormalParameter();
-    await _addProposal_convertToNullAware();
+    if (!_containsErrorCode(
+      {LintNames.prefer_null_aware_operators},
+    )) {
+      await _addProposal_convertToNullAware();
+    }
     await _addProposal_convertToPackageImport();
     await _addProposal_convertToSingleQuotedString();
     await _addProposal_encapsulateField();
@@ -149,11 +132,23 @@
     await _addProposal_splitAndCondition();
     await _addProposal_splitVariableDeclaration();
     await _addProposal_surroundWith();
-    await _addProposal_useCurlyBraces();
+    if (!_containsErrorCode(
+      {LintNames.curly_braces_in_flow_control_structures},
+    )) {
+      await _addProposal_useCurlyBraces();
+    }
 
     if (experimentStatus.control_flow_collections) {
-      await _addProposal_convertConditionalExpressionToIfElement();
-      await _addProposal_convertMapFromIterableToForLiteral();
+      if (!_containsErrorCode(
+        {LintNames.prefer_if_elements_to_conditional_expressions},
+      )) {
+        await _addProposal_convertConditionalExpressionToIfElement();
+      }
+      if (!_containsErrorCode(
+        {LintNames.prefer_for_elements_to_map_fromIterable},
+      )) {
+        await _addProposal_convertMapFromIterableToForLiteral();
+      }
     }
     if (experimentStatus.spread_collections) {
       await _addProposal_convertAddAllToSpread();
@@ -163,7 +158,7 @@
   }
 
   Future<List<Assist>> computeAssist(AssistKind assistKind) async {
-    if (!_setupCompute()) {
+    if (!setupCompute()) {
       return assists;
     }
 
@@ -188,41 +183,11 @@
     return assists;
   }
 
-  FunctionBody getEnclosingFunctionBody() {
-    // TODO(brianwilkerson) Determine whether there is a reason why this method
-    // isn't just "return node.getAncestor((node) => node is FunctionBody);"
-    {
-      FunctionExpression function =
-          node.thisOrAncestorOfType<FunctionExpression>();
-      if (function != null) {
-        return function.body;
-      }
-    }
-    {
-      FunctionDeclaration function =
-          node.thisOrAncestorOfType<FunctionDeclaration>();
-      if (function != null) {
-        return function.functionExpression.body;
-      }
-    }
-    {
-      ConstructorDeclaration constructor =
-          node.thisOrAncestorOfType<ConstructorDeclaration>();
-      if (constructor != null) {
-        return constructor.body;
-      }
-    }
-    {
-      MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
-      if (method != null) {
-        return method.body;
-      }
-    }
-    return null;
-  }
-
   void _addAssistFromBuilder(DartChangeBuilder builder, AssistKind kind,
       {List args = null}) {
+    if (builder == null) {
+      return;
+    }
     SourceChange change = builder.sourceChange;
     if (change.edits.isEmpty) {
       _coverageMarker();
@@ -233,169 +198,7 @@
     assists.add(new Assist(kind, change));
   }
 
-  Future<void> _addProposal_addTypeAnnotation_DeclaredIdentifier() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    DeclaredIdentifier declaredIdentifier =
-        node.thisOrAncestorOfType<DeclaredIdentifier>();
-    if (declaredIdentifier == null) {
-      ForStatement forEach = node.thisOrAncestorMatching(
-          (node) => node is ForStatement && node.forLoopParts is ForEachParts);
-      ForEachParts forEachParts = forEach?.forLoopParts;
-      int offset = node.offset;
-      if (forEach != null &&
-          forEachParts.iterable != null &&
-          offset < forEachParts.iterable.offset) {
-        declaredIdentifier = forEachParts is ForEachPartsWithDeclaration
-            ? forEachParts.loopVariable
-            : null;
-      }
-    }
-    if (declaredIdentifier == null) {
-      _coverageMarker();
-      return;
-    }
-    // Ensure that there isn't already a type annotation.
-    if (declaredIdentifier.type != null) {
-      _coverageMarker();
-      return;
-    }
-    DartType type = declaredIdentifier.identifier.staticType;
-    if (type is! InterfaceType && type is! FunctionType) {
-      _coverageMarker();
-      return;
-    }
-    _configureTargetLocation(node);
-
-    var changeBuilder = _newDartChangeBuilder();
-    bool validChange = true;
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      Token keyword = declaredIdentifier.keyword;
-      if (keyword.keyword == Keyword.VAR) {
-        builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
-          validChange = builder.writeType(type);
-        });
-      } else {
-        builder.addInsertion(declaredIdentifier.identifier.offset,
-            (DartEditBuilder builder) {
-          validChange = builder.writeType(type);
-          builder.write(' ');
-        });
-      }
-    });
-    if (validChange) {
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
-    }
-  }
-
-  Future<void> _addProposal_addTypeAnnotation_SimpleFormalParameter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    AstNode node = this.node;
-    // should be the name of a simple parameter
-    if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
-      _coverageMarker();
-      return;
-    }
-    SimpleIdentifier name = node;
-    SimpleFormalParameter parameter = node.parent;
-    // the parameter should not have a type
-    if (parameter.type != null) {
-      _coverageMarker();
-      return;
-    }
-    // prepare the type
-    DartType type = parameter.declaredElement.type;
-    // TODO(scheglov) If the parameter is in a method declaration, and if the
-    // method overrides a method that has a type for the corresponding
-    // parameter, it would be nice to copy down the type from the overridden
-    // method.
-    if (type is! InterfaceType) {
-      _coverageMarker();
-      return;
-    }
-    // prepare type source
-    _configureTargetLocation(node);
-
-    var changeBuilder = _newDartChangeBuilder();
-    bool validChange = true;
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addInsertion(name.offset, (DartEditBuilder builder) {
-        validChange = builder.writeType(type);
-        builder.write(' ');
-      });
-    });
-    if (validChange) {
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
-    }
-  }
-
-  Future<void> _addProposal_addTypeAnnotation_VariableDeclaration() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    AstNode node = this.node;
-    // prepare VariableDeclarationList
-    VariableDeclarationList declarationList =
-        node.thisOrAncestorOfType<VariableDeclarationList>();
-    if (declarationList == null) {
-      _coverageMarker();
-      return;
-    }
-    // may be has type annotation already
-    if (declarationList.type != null) {
-      _coverageMarker();
-      return;
-    }
-    // prepare single VariableDeclaration
-    List<VariableDeclaration> variables = declarationList.variables;
-    if (variables.length != 1) {
-      _coverageMarker();
-      return;
-    }
-    VariableDeclaration variable = variables[0];
-    // must be not after the name of the variable
-    if (selectionOffset > variable.name.end) {
-      _coverageMarker();
-      return;
-    }
-    // we need an initializer to get the type from
-    Expression initializer = variable.initializer;
-    if (initializer == null) {
-      _coverageMarker();
-      return;
-    }
-    DartType type = initializer.staticType;
-    // prepare type source
-    if ((type is! InterfaceType || type.isDartCoreNull) &&
-        type is! FunctionType) {
-      _coverageMarker();
-      return;
-    }
-    _configureTargetLocation(node);
-
-    var changeBuilder = _newDartChangeBuilder();
-    bool validChange = true;
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      Token keyword = declarationList.keyword;
-      if (keyword?.keyword == Keyword.VAR) {
-        builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
-          validChange = builder.writeType(type);
-        });
-      } else {
-        builder.addInsertion(variable.offset, (DartEditBuilder builder) {
-          validChange = builder.writeType(type);
-          builder.write(' ');
-        });
-      }
-    });
-    if (validChange) {
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
-    }
-  }
-
   Future<void> _addProposal_assignToLocalVariable() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare enclosing ExpressionStatement
     ExpressionStatement expressionStatement;
     for (AstNode node = this.node; node != null; node = node.parent) {
@@ -585,43 +388,12 @@
   }
 
   Future<void> _addProposal_convertConditionalExpressionToIfElement() async {
-    AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
-    if (node == null) {
-      _coverageMarker();
-      return;
-    }
-    AstNode nodeToReplace = node;
-    AstNode parent = node.parent;
-    while (parent is ParenthesizedExpression) {
-      nodeToReplace = parent;
-      parent = parent.parent;
-    }
-    if (parent is ListLiteral || (parent is SetOrMapLiteral && parent.isSet)) {
-      ConditionalExpression conditional = node;
-      Expression condition = conditional.condition.unParenthesized;
-      Expression thenExpression = conditional.thenExpression.unParenthesized;
-      Expression elseExpression = conditional.elseExpression.unParenthesized;
-
-      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-        builder.addReplacement(range.node(nodeToReplace),
-            (DartEditBuilder builder) {
-          builder.write('if (');
-          builder.write(utils.getNodeText(condition));
-          builder.write(') ');
-          builder.write(utils.getNodeText(thenExpression));
-          builder.write(' else ');
-          builder.write(utils.getNodeText(elseExpression));
-        });
-      });
-      _addAssistFromBuilder(
-          changeBuilder, DartAssistKind.CONVERT_TO_IF_ELEMENT);
-    }
+    final changeBuilder =
+        await createBuilder_convertConditionalExpressionToIfElement();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_IF_ELEMENT);
   }
 
   Future<void> _addProposal_convertDocumentationIntoBlock() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     Comment comment = node.thisOrAncestorOfType<Comment>();
     if (comment == null || !comment.isDocumentation) {
       return;
@@ -653,73 +425,12 @@
   }
 
   Future<void> _addProposal_convertDocumentationIntoLine() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    Comment comment = node.thisOrAncestorOfType<Comment>();
-    if (comment == null ||
-        !comment.isDocumentation ||
-        comment.tokens.length != 1) {
-      _coverageMarker();
-      return;
-    }
-    Token token = comment.tokens.first;
-    if (token.type != TokenType.MULTI_LINE_COMMENT) {
-      _coverageMarker();
-      return;
-    }
-    String text = token.lexeme;
-    List<String> lines = text.split('\n');
-    String prefix = utils.getNodePrefix(comment);
-    List<String> newLines = <String>[];
-    bool firstLine = true;
-    String linePrefix = '';
-    for (String line in lines) {
-      if (firstLine) {
-        firstLine = false;
-        String expectedPrefix = '/**';
-        if (!line.startsWith(expectedPrefix)) {
-          _coverageMarker();
-          return;
-        }
-        line = line.substring(expectedPrefix.length).trim();
-        if (line.isNotEmpty) {
-          newLines.add('/// $line');
-          linePrefix = eol + prefix;
-        }
-      } else {
-        if (line.startsWith(prefix + ' */')) {
-          break;
-        }
-        String expectedPrefix = prefix + ' *';
-        if (!line.startsWith(expectedPrefix)) {
-          _coverageMarker();
-          return;
-        }
-        line = line.substring(expectedPrefix.length);
-        if (line.isEmpty) {
-          newLines.add('$linePrefix///');
-        } else {
-          newLines.add('$linePrefix///$line');
-        }
-        linePrefix = eol + prefix;
-      }
-    }
-
-    var changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
-        for (String newLine in newLines) {
-          builder.write(newLine);
-        }
-      });
-    });
+    final changeBuilder = await createBuilder_convertDocumentationIntoLine();
     _addAssistFromBuilder(
         changeBuilder, DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
   }
 
   Future<void> _addProposal_convertIntoFinalField() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // Find the enclosing getter.
     MethodDeclaration getter;
     for (AstNode n = node; n != null; n = n.parent) {
@@ -789,8 +500,6 @@
   }
 
   Future<void> _addProposal_convertIntoGetter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // Find the enclosing field declaration.
     FieldDeclaration fieldDeclaration;
     for (AstNode n = node; n != null; n = n.parent) {
@@ -962,166 +671,12 @@
   }
 
   Future<void> _addProposal_convertMapFromIterableToForLiteral() async {
-    //
-    // Ensure that the selection is inside an invocation of Map.fromIterable.
-    //
-    InstanceCreationExpression creation =
-        node.thisOrAncestorOfType<InstanceCreationExpression>();
-    if (creation == null) {
-      _coverageMarker();
-      return;
-    }
-    ConstructorElement element = creation.staticElement;
-    if (element == null ||
-        element.name != 'fromIterable' ||
-        element.enclosingElement != typeProvider.mapType.element) {
-      _coverageMarker();
-      return;
-    }
-    //
-    // Ensure that the arguments have the right form.
-    //
-    NodeList<Expression> arguments = creation.argumentList.arguments;
-    if (arguments.length != 3) {
-      _coverageMarker();
-      return;
-    }
-    Expression iterator = arguments[0].unParenthesized;
-    Expression secondArg = arguments[1];
-    Expression thirdArg = arguments[2];
-
-    Expression extractBody(FunctionExpression expression) {
-      FunctionBody body = expression.body;
-      if (body is ExpressionFunctionBody) {
-        return body.expression;
-      } else if (body is BlockFunctionBody) {
-        NodeList<Statement> statements = body.block.statements;
-        if (statements.length == 1) {
-          Statement statement = statements[0];
-          if (statement is ReturnStatement) {
-            return statement.expression;
-          }
-        }
-      }
-      return null;
-    }
-
-    FunctionExpression extractClosure(String name, Expression argument) {
-      if (argument is NamedExpression && argument.name.label.name == name) {
-        Expression expression = argument.expression.unParenthesized;
-        if (expression is FunctionExpression) {
-          NodeList<FormalParameter> parameters =
-              expression.parameters.parameters;
-          if (parameters.length == 1 && parameters[0].isRequiredPositional) {
-            if (extractBody(expression) != null) {
-              return expression;
-            }
-          }
-        }
-      }
-      return null;
-    }
-
-    FunctionExpression keyClosure =
-        extractClosure('key', secondArg) ?? extractClosure('key', thirdArg);
-    FunctionExpression valueClosure =
-        extractClosure('value', thirdArg) ?? extractClosure('value', secondArg);
-    if (keyClosure == null || valueClosure == null) {
-      _coverageMarker();
-      return;
-    }
-    //
-    // Compute the loop variable name and convert the key and value closures if
-    // necessary.
-    //
-    SimpleFormalParameter keyParameter = keyClosure.parameters.parameters[0];
-    String keyParameterName = keyParameter.identifier.name;
-    SimpleFormalParameter valueParameter =
-        valueClosure.parameters.parameters[0];
-    String valueParameterName = valueParameter.identifier.name;
-    Expression keyBody = extractBody(keyClosure);
-    String keyExpressionText = utils.getNodeText(keyBody);
-    Expression valueBody = extractBody(valueClosure);
-    String valueExpressionText = utils.getNodeText(valueBody);
-
-    String loopVariableName;
-    if (keyParameterName == valueParameterName) {
-      loopVariableName = keyParameterName;
-    } else {
-      _ParameterReferenceFinder keyFinder =
-          new _ParameterReferenceFinder(keyParameter.declaredElement);
-      keyBody.accept(keyFinder);
-
-      _ParameterReferenceFinder valueFinder =
-          new _ParameterReferenceFinder(valueParameter.declaredElement);
-      valueBody.accept(valueFinder);
-
-      String computeUnusedVariableName() {
-        String candidate = 'e';
-        var index = 1;
-        while (keyFinder.referencesName(candidate) ||
-            valueFinder.referencesName(candidate)) {
-          candidate = 'e${index++}';
-        }
-        return candidate;
-      }
-
-      if (valueFinder.isParameterUnreferenced) {
-        if (valueFinder.referencesName(keyParameterName)) {
-          // The name of the value parameter is not used, but we can't use the
-          // name of the key parameter because doing so would hide a variable
-          // referenced in the value expression.
-          loopVariableName = computeUnusedVariableName();
-          keyExpressionText = keyFinder.replaceName(
-              keyExpressionText, loopVariableName, keyBody.offset);
-        } else {
-          loopVariableName = keyParameterName;
-        }
-      } else if (keyFinder.isParameterUnreferenced) {
-        if (keyFinder.referencesName(valueParameterName)) {
-          // The name of the key parameter is not used, but we can't use the
-          // name of the value parameter because doing so would hide a variable
-          // referenced in the key expression.
-          loopVariableName = computeUnusedVariableName();
-          valueExpressionText = valueFinder.replaceName(
-              valueExpressionText, loopVariableName, valueBody.offset);
-        } else {
-          loopVariableName = valueParameterName;
-        }
-      } else {
-        // The names are different and both are used. We need to find a name
-        // that would not change the resolution of any other identifiers in
-        // either the key or value expressions.
-        loopVariableName = computeUnusedVariableName();
-        keyExpressionText = keyFinder.replaceName(
-            keyExpressionText, loopVariableName, keyBody.offset);
-        valueExpressionText = valueFinder.replaceName(
-            valueExpressionText, loopVariableName, valueBody.offset);
-      }
-    }
-    //
-    // Construct the edit.
-    //
-    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addReplacement(range.node(creation), (DartEditBuilder builder) {
-        builder.write('{ for (var ');
-        builder.write(loopVariableName);
-        builder.write(' in ');
-        builder.write(utils.getNodeText(iterator));
-        builder.write(') ');
-        builder.write(keyExpressionText);
-        builder.write(' : ');
-        builder.write(valueExpressionText);
-        builder.write(' }');
-      });
-    });
+    final changeBuilder =
+        await createBuilder_convertMapFromIterableToForLiteral();
     _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_FOR_ELEMENT);
   }
 
   Future<void> _addProposal_convertPartOfToUri() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     PartOfDirective directive = node.thisOrAncestorOfType<PartOfDirective>();
     if (directive == null || directive.libraryName == null) {
       return;
@@ -1267,8 +822,6 @@
   }
 
   Future<void> _addProposal_convertToBlockFunctionBody() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     FunctionBody body = getEnclosingFunctionBody();
     // prepare expression body
     if (body is! ExpressionFunctionBody || body.isGenerator) {
@@ -1312,67 +865,16 @@
   }
 
   Future<void> _addProposal_convertToDoubleQuotedString() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     await _convertQuotes(false, DartAssistKind.CONVERT_TO_DOUBLE_QUOTED_STRING);
   }
 
   Future<void> _addProposal_convertToExpressionFunctionBody() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    // prepare current body
-    FunctionBody body = getEnclosingFunctionBody();
-    if (body is! BlockFunctionBody || body.isGenerator) {
-      _coverageMarker();
-      return;
-    }
-    // prepare return statement
-    List<Statement> statements = (body as BlockFunctionBody).block.statements;
-    if (statements.length != 1) {
-      _coverageMarker();
-      return;
-    }
-    Statement onlyStatement = statements.first;
-    // prepare returned expression
-    Expression returnExpression;
-    if (onlyStatement is ReturnStatement) {
-      returnExpression = onlyStatement.expression;
-    } else if (onlyStatement is ExpressionStatement) {
-      returnExpression = onlyStatement.expression;
-    }
-    if (returnExpression == null) {
-      _coverageMarker();
-      return;
-    }
-
-    // Return expressions can be quite large, e.g. Flutter build() methods.
-    // It is surprising to see this Quick Assist deep in the function body.
-    if (selectionOffset >= returnExpression.offset) {
-      _coverageMarker();
-      return;
-    }
-
-    var changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addReplacement(range.node(body), (DartEditBuilder builder) {
-        if (body.isAsynchronous) {
-          builder.write('async ');
-        }
-        builder.write('=> ');
-        builder.write(_getNodeText(returnExpression));
-        if (body.parent is! FunctionExpression ||
-            body.parent.parent is FunctionDeclaration) {
-          builder.write(';');
-        }
-      });
-    });
+    final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
     _addAssistFromBuilder(
         changeBuilder, DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
   }
 
   Future<void> _addProposal_convertToFieldParameter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node == null) {
       return;
     }
@@ -1465,8 +967,6 @@
   }
 
   Future<void> _addProposal_convertToForIndexLoop() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // find enclosing ForEachStatement
     ForStatement forEachStatement = node.thisOrAncestorMatching(
         (node) => node is ForStatement && node.forLoopParts is ForEachParts);
@@ -1549,8 +1049,6 @@
   }
 
   Future<void> _addProposal_convertToGenericFunctionSyntax() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     while (node != null) {
       if (node is FunctionTypeAlias) {
@@ -1569,35 +1067,11 @@
   }
 
   Future<void> _addProposal_convertToIntLiteral() async {
-    if (node is! DoubleLiteral) {
-      _coverageMarker();
-      return;
-    }
-    DoubleLiteral literal = node;
-    int intValue;
-    try {
-      intValue = literal.value?.truncate();
-    } catch (e) {
-      // Double cannot be converted to int
-    }
-    if (intValue == null || intValue != literal.value) {
-      _coverageMarker();
-      return;
-    }
-
-    var changeBuilder = _newDartChangeBuilder();
-    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.addReplacement(new SourceRange(literal.offset, literal.length),
-          (DartEditBuilder builder) {
-        builder.write('$intValue');
-      });
-    });
+    final changeBuilder = await createBuilder_convertToIntLiteral();
     _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_INT_LITERAL);
   }
 
   Future<void> _addProposal_convertToIsNot_onIs() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // may be child of "is"
     AstNode node = this.node;
     while (node != null && node is! IsExpression) {
@@ -1649,8 +1123,6 @@
   }
 
   Future<void> _addProposal_convertToIsNot_onNot() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // may be () in prefix expression
     AstNode node = this.node;
     if (node is ParenthesizedExpression && node.parent is PrefixExpression) {
@@ -1706,8 +1178,6 @@
    * Converts "!isEmpty" -> "isNotEmpty" if possible.
    */
   Future<void> _addProposal_convertToIsNotEmpty() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare "expr.isEmpty"
     AstNode isEmptyAccess = null;
     SimpleIdentifier isEmptyIdentifier = null;
@@ -1796,8 +1266,6 @@
   }
 
   Future<void> _addProposal_convertToNormalParameter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier &&
         node.parent is FieldFormalParameter &&
         node.parent.parent is FormalParameterList &&
@@ -1837,92 +1305,8 @@
   }
 
   Future<void> _addProposal_convertToNullAware() async {
-    AstNode node = this.node;
-    if (node is! ConditionalExpression) {
-      _coverageMarker();
-      return;
-    }
-    ConditionalExpression conditional = node;
-    Expression condition = conditional.condition.unParenthesized;
-    SimpleIdentifier identifier;
-    Expression nullExpression;
-    Expression nonNullExpression;
-    int periodOffset;
-
-    if (condition is BinaryExpression) {
-      //
-      // Identify the variable being compared to `null`, or return if the
-      // condition isn't a simple comparison of `null` to a variable's value.
-      //
-      Expression leftOperand = condition.leftOperand;
-      Expression rightOperand = condition.rightOperand;
-      if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
-        identifier = rightOperand;
-      } else if (rightOperand is NullLiteral &&
-          leftOperand is SimpleIdentifier) {
-        identifier = leftOperand;
-      } else {
-        _coverageMarker();
-        return;
-      }
-      if (identifier.staticElement is! LocalElement) {
-        _coverageMarker();
-        return;
-      }
-      //
-      // Identify the expression executed when the variable is `null` and when
-      // it is non-`null`. Return if the `null` expression isn't a null literal
-      // or if the non-`null` expression isn't a method invocation whose target
-      // is the save variable being compared to `null`.
-      //
-      if (condition.operator.type == TokenType.EQ_EQ) {
-        nullExpression = conditional.thenExpression;
-        nonNullExpression = conditional.elseExpression;
-      } else if (condition.operator.type == TokenType.BANG_EQ) {
-        nonNullExpression = conditional.thenExpression;
-        nullExpression = conditional.elseExpression;
-      }
-      if (nullExpression == null || nonNullExpression == null) {
-        _coverageMarker();
-        return;
-      }
-      if (nullExpression.unParenthesized is! NullLiteral) {
-        _coverageMarker();
-        return;
-      }
-      Expression unwrappedExpression = nonNullExpression.unParenthesized;
-      Expression target;
-      Token operator;
-      if (unwrappedExpression is MethodInvocation) {
-        target = unwrappedExpression.target;
-        operator = unwrappedExpression.operator;
-      } else if (unwrappedExpression is PrefixedIdentifier) {
-        target = unwrappedExpression.prefix;
-        operator = unwrappedExpression.period;
-      } else {
-        _coverageMarker();
-        return;
-      }
-      if (operator.type != TokenType.PERIOD) {
-        _coverageMarker();
-        return;
-      }
-      if (!(target is SimpleIdentifier &&
-          target.staticElement == identifier.staticElement)) {
-        _coverageMarker();
-        return;
-      }
-      periodOffset = operator.offset;
-
-      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-        builder.addDeletion(range.startStart(node, nonNullExpression));
-        builder.addSimpleInsertion(periodOffset, '?');
-        builder.addDeletion(range.endEnd(nonNullExpression, node));
-      });
-      _addAssistFromBuilder(
-          changeBuilder, DartAssistKind.CONVERT_TO_NULL_AWARE);
-    }
+    final changeBuilder = await createBuilder_convertToNullAware();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_NULL_AWARE);
   }
 
   Future<void> _addProposal_convertToPackageImport() async {
@@ -1968,14 +1352,10 @@
   }
 
   Future<void> _addProposal_convertToSingleQuotedString() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     await _convertQuotes(true, DartAssistKind.CONVERT_TO_SINGLE_QUOTED_STRING);
   }
 
   Future<void> _addProposal_encapsulateField() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // find FieldDeclaration
     FieldDeclaration fieldDeclaration =
         node.thisOrAncestorOfType<FieldDeclaration>();
@@ -2075,8 +1455,6 @@
   }
 
   Future<void> _addProposal_exchangeOperands() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // check that user invokes quick assist on binary expression
     if (node is! BinaryExpression) {
       _coverageMarker();
@@ -2132,8 +1510,6 @@
   }
 
   Future<void> _addProposal_flutterConvertToChildren() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // Find "child: widget" under selection.
     NamedExpression namedExp;
     {
@@ -2401,8 +1777,6 @@
   }
 
   Future<void> _addProposal_flutterMoveWidgetDown() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var widget = flutter.identifyWidgetExpression(node);
     if (widget == null) {
       return;
@@ -2435,8 +1809,6 @@
   }
 
   Future<void> _addProposal_flutterMoveWidgetUp() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var widget = flutter.identifyWidgetExpression(node);
     if (widget == null) {
       return;
@@ -2468,8 +1840,6 @@
   }
 
   Future<void> _addProposal_flutterRemoveWidget_multipleChildren() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var widgetCreation = flutter.identifyNewExpression(node);
     if (widgetCreation == null) {
       return;
@@ -2508,8 +1878,6 @@
   }
 
   Future<void> _addProposal_flutterRemoveWidget_singleChild() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var widgetCreation = flutter.identifyNewExpression(node);
     if (widgetCreation == null) {
       return;
@@ -2535,8 +1903,6 @@
   }
 
   Future<void> _addProposal_flutterSwapWithChild() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     InstanceCreationExpression parent = flutter.identifyNewExpression(node);
     if (!flutter.isWidgetCreation(parent)) {
       _coverageMarker();
@@ -2556,8 +1922,6 @@
   }
 
   Future<void> _addProposal_flutterSwapWithParent() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     InstanceCreationExpression child = flutter.identifyNewExpression(node);
     if (!flutter.isWidgetCreation(child)) {
       _coverageMarker();
@@ -2635,8 +1999,6 @@
   }
 
   Future<void> _addProposal_flutterWrapWidget() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     await _addProposal_flutterWrapWidgetImpl();
     await _addProposal_flutterWrapWidgetImpl(
         kind: DartAssistKind.FLUTTER_WRAP_CENTER,
@@ -2668,8 +2030,6 @@
       String parentLibraryUri,
       String parentClassName,
       List<String> leadingLines = const []}) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     Expression widgetExpr = flutter.identifyWidgetExpression(node);
     if (widgetExpr == null) {
       _coverageMarker();
@@ -2730,8 +2090,6 @@
   }
 
   Future<void> _addProposal_flutterWrapWidgets() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var selectionRange = new SourceRange(selectionOffset, selectionLength);
     var analyzer = new SelectionAnalyzer(selectionRange);
     context.resolveResult.unit.accept(analyzer);
@@ -2763,8 +2121,6 @@
         {@required AssistKind kind,
         @required String parentLibraryUri,
         @required String parentClassName}) async {
-      // TODO(brianwilkerson) Determine whether this await is necessary.
-      await null;
       ClassElement parentClassElement =
           await sessionHelper.getClass(parentLibraryUri, parentClassName);
       ClassElement widgetClassElement =
@@ -2819,8 +2175,6 @@
   }
 
   Future<void> _addProposal_importAddShow() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare ImportDirective
     ImportDirective importDirective =
         node.thisOrAncestorOfType<ImportDirective>();
@@ -2906,8 +2260,6 @@
   }
 
   Future<void> _addProposal_introduceLocalTestedType() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is IfStatement) {
       node = (node as IfStatement).condition;
@@ -2979,8 +2331,6 @@
   }
 
   Future<void> _addProposal_invertIf() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! IfStatement) {
       return;
     }
@@ -3007,8 +2357,6 @@
   }
 
   Future<void> _addProposal_joinIfStatementInner() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // climb up condition to the (supposedly) "if" statement
     AstNode node = this.node;
     while (node is Expression) {
@@ -3069,8 +2417,6 @@
   }
 
   Future<void> _addProposal_joinIfStatementOuter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // climb up condition to the (supposedly) "if" statement
     AstNode node = this.node;
     while (node is Expression) {
@@ -3135,8 +2481,6 @@
   }
 
   Future<void> _addProposal_joinVariableDeclaration_onAssignment() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // check that node is LHS in assignment
     if (node is SimpleIdentifier &&
         node.parent is AssignmentExpression &&
@@ -3213,8 +2557,6 @@
   }
 
   Future<void> _addProposal_joinVariableDeclaration_onDeclaration() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare enclosing VariableDeclarationList
     VariableDeclarationList declList =
         node.thisOrAncestorOfType<VariableDeclarationList>();
@@ -3283,8 +2625,6 @@
   }
 
   Future<void> _addProposal_removeTypeAnnotation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     VariableDeclarationList declarationList =
         node.thisOrAncestorOfType<VariableDeclarationList>();
     if (declarationList == null) {
@@ -3329,8 +2669,6 @@
   }
 
   Future<void> _addProposal_reparentFlutterList() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! ListLiteral) {
       return;
     }
@@ -3377,8 +2715,6 @@
   }
 
   Future<void> _addProposal_replaceConditionalWithIfElse() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     ConditionalExpression conditional = null;
     // may be on Statement with Conditional
     Statement statement = node.thisOrAncestorOfType<Statement>();
@@ -3483,8 +2819,6 @@
   }
 
   Future<void> _addProposal_replaceIfElseWithConditional() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // should be "if"
     if (node is! IfStatement) {
       _coverageMarker();
@@ -3592,8 +2926,6 @@
   }
 
   Future<void> _addProposal_splitAndCondition() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // check that user invokes quick assist on binary expression
     if (node is! BinaryExpression) {
       _coverageMarker();
@@ -3733,8 +3065,6 @@
   }
 
   Future<void> _addProposal_surroundWith() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare selected statements
     List<Statement> selectedStatements;
     {
@@ -3949,129 +3279,21 @@
   }
 
   Future<void> _addProposal_useCurlyBraces() async {
-    Future<void> doStatement(DoStatement node) async {
-      var body = node.body;
-      if (body is Block) return;
+    final changeBuilder = await createBuilder_useCurlyBraces();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
+  }
 
-      var prefix = utils.getLinePrefix(node.offset);
-      var indent = prefix + utils.getIndent(1);
+  Future<void> _addProposals_addTypeAnnotation() async {
+    var changeBuilder =
+        await createBuilder_addTypeAnnotation_DeclaredIdentifier();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
 
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (builder) {
-        builder.addSimpleReplacement(
-          range.endStart(node.doKeyword, body),
-          ' {$eol$indent',
-        );
-        builder.addSimpleReplacement(
-          range.endStart(body, node.whileKeyword),
-          '$eol$prefix} ',
-        );
-      });
+    changeBuilder =
+        await createBuilder_addTypeAnnotation_SimpleFormalParameter();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
 
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
-    }
-
-    Future<void> forStatement(ForStatement node) async {
-      var body = node.body;
-      if (body is Block) return;
-
-      var prefix = utils.getLinePrefix(node.offset);
-      var indent = prefix + utils.getIndent(1);
-
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (builder) {
-        builder.addSimpleReplacement(
-          range.endStart(node.rightParenthesis, body),
-          ' {$eol$indent',
-        );
-        builder.addSimpleInsertion(body.end, '$eol$prefix}');
-      });
-
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
-    }
-
-    Future<void> ifStatement(IfStatement node, Statement thenOrElse) async {
-      var prefix = utils.getLinePrefix(node.offset);
-      var indent = prefix + utils.getIndent(1);
-
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (builder) {
-        var thenStatement = node.thenStatement;
-        if (thenStatement is! Block &&
-            (thenOrElse == null || thenOrElse == thenStatement)) {
-          builder.addSimpleReplacement(
-            range.endStart(node.rightParenthesis, thenStatement),
-            ' {$eol$indent',
-          );
-          if (node.elseKeyword != null) {
-            builder.addSimpleReplacement(
-              range.endStart(thenStatement, node.elseKeyword),
-              '$eol$prefix} ',
-            );
-          } else {
-            builder.addSimpleInsertion(thenStatement.end, '$eol$prefix}');
-          }
-        }
-
-        var elseStatement = node.elseStatement;
-        if (elseStatement != null &&
-            elseStatement is! Block &&
-            (thenOrElse == null || thenOrElse == elseStatement)) {
-          builder.addSimpleReplacement(
-            range.endStart(node.elseKeyword, elseStatement),
-            ' {$eol$indent',
-          );
-          builder.addSimpleInsertion(elseStatement.end, '$eol$prefix}');
-        }
-      });
-
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
-    }
-
-    Future<void> whileStatement(WhileStatement node) async {
-      var body = node.body;
-      if (body is Block) return;
-
-      var prefix = utils.getLinePrefix(node.offset);
-      var indent = prefix + utils.getIndent(1);
-
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(file, (builder) {
-        builder.addSimpleReplacement(
-          range.endStart(node.rightParenthesis, body),
-          ' {$eol$indent',
-        );
-        builder.addSimpleInsertion(body.end, '$eol$prefix}');
-      });
-
-      _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
-    }
-
-    var statement = this.node.thisOrAncestorOfType<Statement>();
-    var parent = statement?.parent;
-
-    if (statement is DoStatement) {
-      return doStatement(statement);
-    } else if (parent is DoStatement) {
-      return doStatement(parent);
-    } else if (statement is ForStatement) {
-      return forStatement(statement);
-    } else if (parent is ForStatement) {
-      return forStatement(parent);
-    } else if (statement is IfStatement) {
-      if (statement.elseKeyword != null &&
-          range.token(statement.elseKeyword).contains(selectionOffset)) {
-        return ifStatement(statement, statement.elseStatement);
-      } else {
-        return ifStatement(statement, null);
-      }
-    } else if (parent is IfStatement) {
-      return ifStatement(parent, statement);
-    } else if (statement is WhileStatement) {
-      return whileStatement(statement);
-    } else if (parent is WhileStatement) {
-      return whileStatement(parent);
-    }
+    changeBuilder = await createBuilder_addTypeAnnotation_VariableDeclaration();
+    _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
   /**
@@ -4094,18 +3316,20 @@
     return true;
   }
 
-  /**
-   * Configures [utils] using given [target].
-   */
-  void _configureTargetLocation(Object target) {
-    utils.targetClassElement = null;
-    if (target is AstNode) {
-      ClassDeclaration targetClassDeclaration =
-          target.thisOrAncestorOfType<ClassDeclaration>();
-      if (targetClassDeclaration != null) {
-        utils.targetClassElement = targetClassDeclaration.declaredElement;
+  bool _containsErrorCode(Set<String> errorCodes) {
+    final fileOffset = node.offset;
+    for (var error in context.resolveResult.errors) {
+      final errorSource = error.source;
+      if (file == errorSource.fullName) {
+        if (fileOffset >= error.offset &&
+            fileOffset <= error.offset + error.length) {
+          if (errorCodes.contains(error.errorCode.name)) {
+            return true;
+          }
+        }
       }
     }
+    return false;
   }
 
   void _convertFlutterChildToChildren(
@@ -4153,8 +3377,6 @@
 
   Future<void> _convertFunctionTypeAliasToGenericTypeAlias(
       FunctionTypeAlias node) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (!_allParametersHaveTypes(node.parameters)) {
       return;
     }
@@ -4184,8 +3406,6 @@
 
   Future<void> _convertFunctionTypedFormalParameterToSimpleFormalParameter(
       FunctionTypedFormalParameter node) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (!_allParametersHaveTypes(node.parameters)) {
       return;
     }
@@ -4212,8 +3432,6 @@
   }
 
   Future<void> _convertQuotes(bool fromDouble, AssistKind kind) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleStringLiteral) {
       SimpleStringLiteral literal = node;
       if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
@@ -4313,16 +3531,8 @@
     return new DartChangeBuilderImpl.forWorkspace(context.workspace);
   }
 
-  bool _setupCompute() {
-    var locator = new NodeLocator(selectionOffset, selectionEnd);
-    node = locator.searchWithin(context.resolveResult.unit);
-    return node != null;
-  }
-
   Future<void> _swapParentAndChild(InstanceCreationExpression parent,
       InstanceCreationExpression child, AssistKind kind) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // The child must have its own child.
     if (flutter.findChildArgument(child) == null) {
       _coverageMarker();
@@ -4457,70 +3667,6 @@
   }
 }
 
-/**
- * A visitor that can be used to find references to a parameter.
- */
-class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
-  /**
-   * The parameter for which references are being sought, or `null` if we are
-   * just accumulating a list of referenced names.
-   */
-  final ParameterElement parameter;
-
-  /**
-   * A list of the simple identifiers that reference the [parameter].
-   */
-  final List<SimpleIdentifier> references = <SimpleIdentifier>[];
-
-  /**
-   * A collection of the names of other simple identifiers that were found. We
-   * need to know these in order to ensure that the selected loop variable does
-   * not hide a name from an enclosing scope that is already being referenced.
-   */
-  final Set<String> otherNames = new Set<String>();
-
-  /**
-   * Initialize a newly created finder to find references to the [parameter].
-   */
-  _ParameterReferenceFinder(this.parameter) : assert(parameter != null);
-
-  /**
-   * Return `true` if the parameter is unreferenced in the nodes that have been
-   * visited.
-   */
-  bool get isParameterUnreferenced => references.isEmpty;
-
-  /**
-   * Return `true` is the given name (assumed to be different than the name of
-   * the parameter) is references in the nodes that have been visited.
-   */
-  bool referencesName(String name) => otherNames.contains(name);
-
-  /**
-   * Replace all of the references to the parameter in the given [source] with
-   * the [newName]. The [offset] is the offset of the first character of the
-   * [source] relative to the start of the file.
-   */
-  String replaceName(String source, String newName, int offset) {
-    int oldLength = parameter.name.length;
-    for (int i = references.length - 1; i >= 0; i--) {
-      int oldOffset = references[i].offset - offset;
-      source = source.replaceRange(oldOffset, oldOffset + oldLength, newName);
-    }
-    return source;
-  }
-
-  @override
-  void visitSimpleIdentifier(SimpleIdentifier node) {
-    if (node.staticElement == parameter) {
-      references.add(node);
-    } else if (!node.isQualified) {
-      // Only non-prefixed identifiers can be hidden.
-      otherNames.add(node.name);
-    }
-  }
-}
-
 class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor {
   final _SimpleIdentifierVisitor visitor;
 
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
new file mode 100644
index 0000000..a67b7ca
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -0,0 +1,882 @@
+// 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/util.dart';
+import 'package:analysis_server/src/utilities/flutter.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/dart/analysis/session_helper.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:meta/meta.dart';
+
+/// Base class for common processor functionality.
+abstract class BaseProcessor {
+  final int selectionOffset;
+  final int selectionLength;
+  final int selectionEnd;
+
+  final CorrectionUtils utils;
+  final String file;
+
+  final TypeProvider typeProvider;
+  final Flutter flutter;
+
+  final AnalysisSession session;
+  final AnalysisSessionHelper sessionHelper;
+  final ResolvedUnitResult resolvedResult;
+  final ChangeWorkspace workspace;
+
+  AstNode node;
+
+  BaseProcessor({
+    this.selectionOffset = -1,
+    this.selectionLength = 0,
+    @required this.resolvedResult,
+    @required this.workspace,
+  })  : file = resolvedResult.path,
+        flutter = Flutter.of(resolvedResult),
+        session = resolvedResult.session,
+        sessionHelper = AnalysisSessionHelper(resolvedResult.session),
+        typeProvider = resolvedResult.typeProvider,
+        selectionEnd = (selectionOffset ?? 0) + (selectionLength ?? 0),
+        utils = CorrectionUtils(resolvedResult);
+
+  /// Returns the EOL to use for this [CompilationUnit].
+  String get eol => utils.endOfLine;
+
+  /// Return the status of known experiments.
+  ExperimentStatus get experimentStatus =>
+      (session.analysisContext.analysisOptions as AnalysisOptionsImpl)
+          .experimentStatus;
+
+  Future<ChangeBuilder>
+      createBuilder_addTypeAnnotation_DeclaredIdentifier() async {
+    DeclaredIdentifier declaredIdentifier =
+        node.thisOrAncestorOfType<DeclaredIdentifier>();
+    if (declaredIdentifier == null) {
+      ForStatement forEach = node.thisOrAncestorMatching(
+          (node) => node is ForStatement && node.forLoopParts is ForEachParts);
+      ForEachParts forEachParts = forEach?.forLoopParts;
+      int offset = node.offset;
+      if (forEach != null &&
+          forEachParts.iterable != null &&
+          offset < forEachParts.iterable.offset) {
+        declaredIdentifier = forEachParts is ForEachPartsWithDeclaration
+            ? forEachParts.loopVariable
+            : null;
+      }
+    }
+    if (declaredIdentifier == null) {
+      _coverageMarker();
+      return null;
+    }
+    // Ensure that there isn't already a type annotation.
+    if (declaredIdentifier.type != null) {
+      _coverageMarker();
+      return null;
+    }
+    DartType type = declaredIdentifier.identifier.staticType;
+    if (type is! InterfaceType && type is! FunctionType) {
+      _coverageMarker();
+      return null;
+    }
+    _configureTargetLocation(node);
+
+    var changeBuilder = _newDartChangeBuilder();
+    bool validChange = true;
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      Token keyword = declaredIdentifier.keyword;
+      if (keyword.keyword == Keyword.VAR) {
+        builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
+          validChange = builder.writeType(type);
+        });
+      } else {
+        builder.addInsertion(declaredIdentifier.identifier.offset,
+            (DartEditBuilder builder) {
+          validChange = builder.writeType(type);
+          builder.write(' ');
+        });
+      }
+    });
+    return validChange ? changeBuilder : null;
+  }
+
+  Future<ChangeBuilder>
+      createBuilder_addTypeAnnotation_SimpleFormalParameter() async {
+    AstNode node = this.node;
+    // should be the name of a simple parameter
+    if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
+      _coverageMarker();
+      return null;
+    }
+    SimpleIdentifier name = node;
+    SimpleFormalParameter parameter = node.parent;
+    // the parameter should not have a type
+    if (parameter.type != null) {
+      _coverageMarker();
+      return null;
+    }
+    // prepare the type
+    DartType type = parameter.declaredElement.type;
+    // TODO(scheglov) If the parameter is in a method declaration, and if the
+    // method overrides a method that has a type for the corresponding
+    // parameter, it would be nice to copy down the type from the overridden
+    // method.
+    if (type is! InterfaceType) {
+      _coverageMarker();
+      return null;
+    }
+    // prepare type source
+    _configureTargetLocation(node);
+
+    var changeBuilder = _newDartChangeBuilder();
+    bool validChange = true;
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addInsertion(name.offset, (DartEditBuilder builder) {
+        validChange = builder.writeType(type);
+        builder.write(' ');
+      });
+    });
+    return validChange ? changeBuilder : null;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertToNullAware() async {
+    AstNode node = this.node;
+    if (node is! ConditionalExpression) {
+      _coverageMarker();
+      return null;
+    }
+    ConditionalExpression conditional = node;
+    Expression condition = conditional.condition.unParenthesized;
+    SimpleIdentifier identifier;
+    Expression nullExpression;
+    Expression nonNullExpression;
+    int periodOffset;
+
+    if (condition is BinaryExpression) {
+      //
+      // Identify the variable being compared to `null`, or return if the
+      // condition isn't a simple comparison of `null` to a variable's value.
+      //
+      Expression leftOperand = condition.leftOperand;
+      Expression rightOperand = condition.rightOperand;
+      if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
+        identifier = rightOperand;
+      } else if (rightOperand is NullLiteral &&
+          leftOperand is SimpleIdentifier) {
+        identifier = leftOperand;
+      } else {
+        _coverageMarker();
+        return null;
+      }
+      if (identifier.staticElement is! LocalElement) {
+        _coverageMarker();
+        return null;
+      }
+      //
+      // Identify the expression executed when the variable is `null` and when
+      // it is non-`null`. Return if the `null` expression isn't a null literal
+      // or if the non-`null` expression isn't a method invocation whose target
+      // is the save variable being compared to `null`.
+      //
+      if (condition.operator.type == TokenType.EQ_EQ) {
+        nullExpression = conditional.thenExpression;
+        nonNullExpression = conditional.elseExpression;
+      } else if (condition.operator.type == TokenType.BANG_EQ) {
+        nonNullExpression = conditional.thenExpression;
+        nullExpression = conditional.elseExpression;
+      }
+      if (nullExpression == null || nonNullExpression == null) {
+        _coverageMarker();
+        return null;
+      }
+      if (nullExpression.unParenthesized is! NullLiteral) {
+        _coverageMarker();
+        return null;
+      }
+      Expression unwrappedExpression = nonNullExpression.unParenthesized;
+      Expression target;
+      Token operator;
+      if (unwrappedExpression is MethodInvocation) {
+        target = unwrappedExpression.target;
+        operator = unwrappedExpression.operator;
+      } else if (unwrappedExpression is PrefixedIdentifier) {
+        target = unwrappedExpression.prefix;
+        operator = unwrappedExpression.period;
+      } else {
+        _coverageMarker();
+        return null;
+      }
+      if (operator.type != TokenType.PERIOD) {
+        _coverageMarker();
+        return null;
+      }
+      if (!(target is SimpleIdentifier &&
+          target.staticElement == identifier.staticElement)) {
+        _coverageMarker();
+        return null;
+      }
+      periodOffset = operator.offset;
+
+      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addDeletion(range.startStart(node, nonNullExpression));
+        builder.addSimpleInsertion(periodOffset, '?');
+        builder.addDeletion(range.endEnd(nonNullExpression, node));
+      });
+      return changeBuilder;
+    }
+    return null;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
+    // prepare current body
+    FunctionBody body = getEnclosingFunctionBody();
+    if (body is! BlockFunctionBody || body.isGenerator) {
+      _coverageMarker();
+      return null;
+    }
+    // prepare return statement
+    List<Statement> statements = (body as BlockFunctionBody).block.statements;
+    if (statements.length != 1) {
+      _coverageMarker();
+      return null;
+    }
+    Statement onlyStatement = statements.first;
+    // prepare returned expression
+    Expression returnExpression;
+    if (onlyStatement is ReturnStatement) {
+      returnExpression = onlyStatement.expression;
+    } else if (onlyStatement is ExpressionStatement) {
+      returnExpression = onlyStatement.expression;
+    }
+    if (returnExpression == null) {
+      _coverageMarker();
+      return null;
+    }
+
+    // Return expressions can be quite large, e.g. Flutter build() methods.
+    // It is surprising to see this Quick Assist deep in the function body.
+    if (selectionOffset >= returnExpression.offset) {
+      _coverageMarker();
+      return null;
+    }
+
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addReplacement(range.node(body), (DartEditBuilder builder) {
+        if (body.isAsynchronous) {
+          builder.write('async ');
+        }
+        builder.write('=> ');
+        builder.write(_getNodeText(returnExpression));
+        if (body.parent is! FunctionExpression ||
+            body.parent.parent is FunctionDeclaration) {
+          builder.write(';');
+        }
+      });
+    });
+    return changeBuilder;
+  }
+
+  /// Returns the text of the given node in the unit.
+  String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
+      utils.getNodeText(node);
+
+  FunctionBody getEnclosingFunctionBody() {
+    // TODO(brianwilkerson) Determine whether there is a reason why this method
+    // isn't just "return node.getAncestor((node) => node is FunctionBody);"
+    {
+      FunctionExpression function =
+          node.thisOrAncestorOfType<FunctionExpression>();
+      if (function != null) {
+        return function.body;
+      }
+    }
+    {
+      FunctionDeclaration function =
+          node.thisOrAncestorOfType<FunctionDeclaration>();
+      if (function != null) {
+        return function.functionExpression.body;
+      }
+    }
+    {
+      ConstructorDeclaration constructor =
+          node.thisOrAncestorOfType<ConstructorDeclaration>();
+      if (constructor != null) {
+        return constructor.body;
+      }
+    }
+    {
+      MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
+      if (method != null) {
+        return method.body;
+      }
+    }
+    return null;
+  }
+
+  Future<ChangeBuilder>
+      createBuilder_addTypeAnnotation_VariableDeclaration() async {
+    AstNode node = this.node;
+    // prepare VariableDeclarationList
+    VariableDeclarationList declarationList =
+        node.thisOrAncestorOfType<VariableDeclarationList>();
+    if (declarationList == null) {
+      _coverageMarker();
+      return null;
+    }
+    // may be has type annotation already
+    if (declarationList.type != null) {
+      _coverageMarker();
+      return null;
+    }
+    // prepare single VariableDeclaration
+    List<VariableDeclaration> variables = declarationList.variables;
+    if (variables.length != 1) {
+      _coverageMarker();
+      return null;
+    }
+    VariableDeclaration variable = variables[0];
+    // must be not after the name of the variable
+    if (selectionOffset > variable.name.end) {
+      _coverageMarker();
+      return null;
+    }
+    // we need an initializer to get the type from
+    Expression initializer = variable.initializer;
+    if (initializer == null) {
+      _coverageMarker();
+      return null;
+    }
+    DartType type = initializer.staticType;
+    // prepare type source
+    if ((type is! InterfaceType || type.isDartCoreNull) &&
+        type is! FunctionType) {
+      _coverageMarker();
+      return null;
+    }
+    _configureTargetLocation(node);
+
+    var changeBuilder = _newDartChangeBuilder();
+    bool validChange = true;
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      Token keyword = declarationList.keyword;
+      if (keyword?.keyword == Keyword.VAR) {
+        builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
+          validChange = builder.writeType(type);
+        });
+      } else {
+        builder.addInsertion(variable.offset, (DartEditBuilder builder) {
+          validChange = builder.writeType(type);
+          builder.write(' ');
+        });
+      }
+    });
+    return validChange ? changeBuilder : null;
+  }
+
+  Future<ChangeBuilder>
+      createBuilder_convertConditionalExpressionToIfElement() async {
+    AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
+    if (node == null) {
+      _coverageMarker();
+      return null;
+    }
+    AstNode nodeToReplace = node;
+    AstNode parent = node.parent;
+    while (parent is ParenthesizedExpression) {
+      nodeToReplace = parent;
+      parent = parent.parent;
+    }
+    if (parent is ListLiteral || (parent is SetOrMapLiteral && parent.isSet)) {
+      ConditionalExpression conditional = node;
+      Expression condition = conditional.condition.unParenthesized;
+      Expression thenExpression = conditional.thenExpression.unParenthesized;
+      Expression elseExpression = conditional.elseExpression.unParenthesized;
+
+      DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addReplacement(range.node(nodeToReplace),
+            (DartEditBuilder builder) {
+          builder.write('if (');
+          builder.write(utils.getNodeText(condition));
+          builder.write(') ');
+          builder.write(utils.getNodeText(thenExpression));
+          builder.write(' else ');
+          builder.write(utils.getNodeText(elseExpression));
+        });
+      });
+      return changeBuilder;
+    }
+
+    return null;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertDocumentationIntoLine() async {
+    Comment comment = node.thisOrAncestorOfType<Comment>();
+    if (comment == null ||
+        !comment.isDocumentation ||
+        comment.tokens.length != 1) {
+      _coverageMarker();
+      return null;
+    }
+    Token token = comment.tokens.first;
+    if (token.type != TokenType.MULTI_LINE_COMMENT) {
+      _coverageMarker();
+      return null;
+    }
+    String text = token.lexeme;
+    List<String> lines = text.split('\n');
+    String prefix = utils.getNodePrefix(comment);
+    List<String> newLines = <String>[];
+    bool firstLine = true;
+    String linePrefix = '';
+    for (String line in lines) {
+      if (firstLine) {
+        firstLine = false;
+        String expectedPrefix = '/**';
+        if (!line.startsWith(expectedPrefix)) {
+          _coverageMarker();
+          return null;
+        }
+        line = line.substring(expectedPrefix.length).trim();
+        if (line.isNotEmpty) {
+          newLines.add('/// $line');
+          linePrefix = eol + prefix;
+        }
+      } else {
+        if (line.startsWith(prefix + ' */')) {
+          break;
+        }
+        String expectedPrefix = prefix + ' *';
+        if (!line.startsWith(expectedPrefix)) {
+          _coverageMarker();
+          return null;
+        }
+        line = line.substring(expectedPrefix.length);
+        if (line.isEmpty) {
+          newLines.add('$linePrefix///');
+        } else {
+          newLines.add('$linePrefix///$line');
+        }
+        linePrefix = eol + prefix;
+      }
+    }
+
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
+        for (String newLine in newLines) {
+          builder.write(newLine);
+        }
+      });
+    });
+    return changeBuilder;
+  }
+
+  Future<ChangeBuilder>
+      createBuilder_convertMapFromIterableToForLiteral() async {
+    //
+    // Ensure that the selection is inside an invocation of Map.fromIterable.
+    //
+    InstanceCreationExpression creation =
+        node.thisOrAncestorOfType<InstanceCreationExpression>();
+    if (creation == null) {
+      _coverageMarker();
+      return null;
+    }
+    ConstructorElement element = creation.staticElement;
+    if (element == null ||
+        element.name != 'fromIterable' ||
+        element.enclosingElement != typeProvider.mapType.element) {
+      _coverageMarker();
+      return null;
+    }
+    //
+    // Ensure that the arguments have the right form.
+    //
+    NodeList<Expression> arguments = creation.argumentList.arguments;
+    if (arguments.length != 3) {
+      _coverageMarker();
+      return null;
+    }
+    Expression iterator = arguments[0].unParenthesized;
+    Expression secondArg = arguments[1];
+    Expression thirdArg = arguments[2];
+
+    Expression extractBody(FunctionExpression expression) {
+      FunctionBody body = expression.body;
+      if (body is ExpressionFunctionBody) {
+        return body.expression;
+      } else if (body is BlockFunctionBody) {
+        NodeList<Statement> statements = body.block.statements;
+        if (statements.length == 1) {
+          Statement statement = statements[0];
+          if (statement is ReturnStatement) {
+            return statement.expression;
+          }
+        }
+      }
+      return null;
+    }
+
+    FunctionExpression extractClosure(String name, Expression argument) {
+      if (argument is NamedExpression && argument.name.label.name == name) {
+        Expression expression = argument.expression.unParenthesized;
+        if (expression is FunctionExpression) {
+          NodeList<FormalParameter> parameters =
+              expression.parameters.parameters;
+          if (parameters.length == 1 && parameters[0].isRequiredPositional) {
+            if (extractBody(expression) != null) {
+              return expression;
+            }
+          }
+        }
+      }
+      return null;
+    }
+
+    FunctionExpression keyClosure =
+        extractClosure('key', secondArg) ?? extractClosure('key', thirdArg);
+    FunctionExpression valueClosure =
+        extractClosure('value', thirdArg) ?? extractClosure('value', secondArg);
+    if (keyClosure == null || valueClosure == null) {
+      _coverageMarker();
+      return null;
+    }
+    //
+    // Compute the loop variable name and convert the key and value closures if
+    // necessary.
+    //
+    SimpleFormalParameter keyParameter = keyClosure.parameters.parameters[0];
+    String keyParameterName = keyParameter.identifier.name;
+    SimpleFormalParameter valueParameter =
+        valueClosure.parameters.parameters[0];
+    String valueParameterName = valueParameter.identifier.name;
+    Expression keyBody = extractBody(keyClosure);
+    String keyExpressionText = utils.getNodeText(keyBody);
+    Expression valueBody = extractBody(valueClosure);
+    String valueExpressionText = utils.getNodeText(valueBody);
+
+    String loopVariableName;
+    if (keyParameterName == valueParameterName) {
+      loopVariableName = keyParameterName;
+    } else {
+      _ParameterReferenceFinder keyFinder =
+          new _ParameterReferenceFinder(keyParameter.declaredElement);
+      keyBody.accept(keyFinder);
+
+      _ParameterReferenceFinder valueFinder =
+          new _ParameterReferenceFinder(valueParameter.declaredElement);
+      valueBody.accept(valueFinder);
+
+      String computeUnusedVariableName() {
+        String candidate = 'e';
+        var index = 1;
+        while (keyFinder.referencesName(candidate) ||
+            valueFinder.referencesName(candidate)) {
+          candidate = 'e${index++}';
+        }
+        return candidate;
+      }
+
+      if (valueFinder.isParameterUnreferenced) {
+        if (valueFinder.referencesName(keyParameterName)) {
+          // The name of the value parameter is not used, but we can't use the
+          // name of the key parameter because doing so would hide a variable
+          // referenced in the value expression.
+          loopVariableName = computeUnusedVariableName();
+          keyExpressionText = keyFinder.replaceName(
+              keyExpressionText, loopVariableName, keyBody.offset);
+        } else {
+          loopVariableName = keyParameterName;
+        }
+      } else if (keyFinder.isParameterUnreferenced) {
+        if (keyFinder.referencesName(valueParameterName)) {
+          // The name of the key parameter is not used, but we can't use the
+          // name of the value parameter because doing so would hide a variable
+          // referenced in the key expression.
+          loopVariableName = computeUnusedVariableName();
+          valueExpressionText = valueFinder.replaceName(
+              valueExpressionText, loopVariableName, valueBody.offset);
+        } else {
+          loopVariableName = valueParameterName;
+        }
+      } else {
+        // The names are different and both are used. We need to find a name
+        // that would not change the resolution of any other identifiers in
+        // either the key or value expressions.
+        loopVariableName = computeUnusedVariableName();
+        keyExpressionText = keyFinder.replaceName(
+            keyExpressionText, loopVariableName, keyBody.offset);
+        valueExpressionText = valueFinder.replaceName(
+            valueExpressionText, loopVariableName, valueBody.offset);
+      }
+    }
+    //
+    // Construct the edit.
+    //
+    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addReplacement(range.node(creation), (DartEditBuilder builder) {
+        builder.write('{ for (var ');
+        builder.write(loopVariableName);
+        builder.write(' in ');
+        builder.write(utils.getNodeText(iterator));
+        builder.write(') ');
+        builder.write(keyExpressionText);
+        builder.write(' : ');
+        builder.write(valueExpressionText);
+        builder.write(' }');
+      });
+    });
+    return changeBuilder;
+  }
+
+  Future<ChangeBuilder> createBuilder_convertToIntLiteral() async {
+    if (node is! DoubleLiteral) {
+      _coverageMarker();
+      return null;
+    }
+    DoubleLiteral literal = node;
+    int intValue;
+    try {
+      intValue = literal.value?.truncate();
+    } catch (e) {
+      // Double cannot be converted to int
+    }
+    if (intValue == null || intValue != literal.value) {
+      _coverageMarker();
+      return null;
+    }
+
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addReplacement(new SourceRange(literal.offset, literal.length),
+          (DartEditBuilder builder) {
+        builder.write('$intValue');
+      });
+    });
+    return changeBuilder;
+  }
+
+  @protected
+  Future<ChangeBuilder> createBuilder_useCurlyBraces() async {
+    Future<ChangeBuilder> doStatement(DoStatement node) async {
+      var body = node.body;
+      if (body is Block) return null;
+
+      var prefix = utils.getLinePrefix(node.offset);
+      var indent = prefix + utils.getIndent(1);
+
+      var changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+          range.endStart(node.doKeyword, body),
+          ' {$eol$indent',
+        );
+        builder.addSimpleReplacement(
+          range.endStart(body, node.whileKeyword),
+          '$eol$prefix} ',
+        );
+      });
+      return changeBuilder;
+    }
+
+    Future<ChangeBuilder> forStatement(ForStatement node) async {
+      var body = node.body;
+      if (body is Block) return null;
+
+      var prefix = utils.getLinePrefix(node.offset);
+      var indent = prefix + utils.getIndent(1);
+
+      var changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+          range.endStart(node.rightParenthesis, body),
+          ' {$eol$indent',
+        );
+        builder.addSimpleInsertion(body.end, '$eol$prefix}');
+      });
+
+      return changeBuilder;
+    }
+
+    Future<ChangeBuilder> ifStatement(
+        IfStatement node, Statement thenOrElse) async {
+      var prefix = utils.getLinePrefix(node.offset);
+      var indent = prefix + utils.getIndent(1);
+
+      var changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (builder) {
+        var thenStatement = node.thenStatement;
+        if (thenStatement is! Block &&
+            (thenOrElse == null || thenOrElse == thenStatement)) {
+          builder.addSimpleReplacement(
+            range.endStart(node.rightParenthesis, thenStatement),
+            ' {$eol$indent',
+          );
+          if (node.elseKeyword != null) {
+            builder.addSimpleReplacement(
+              range.endStart(thenStatement, node.elseKeyword),
+              '$eol$prefix} ',
+            );
+          } else {
+            builder.addSimpleInsertion(thenStatement.end, '$eol$prefix}');
+          }
+        }
+
+        var elseStatement = node.elseStatement;
+        if (elseStatement != null &&
+            elseStatement is! Block &&
+            (thenOrElse == null || thenOrElse == elseStatement)) {
+          builder.addSimpleReplacement(
+            range.endStart(node.elseKeyword, elseStatement),
+            ' {$eol$indent',
+          );
+          builder.addSimpleInsertion(elseStatement.end, '$eol$prefix}');
+        }
+      });
+
+      return changeBuilder;
+    }
+
+    Future<ChangeBuilder> whileStatement(WhileStatement node) async {
+      var body = node.body;
+      if (body is Block) return null;
+
+      var prefix = utils.getLinePrefix(node.offset);
+      var indent = prefix + utils.getIndent(1);
+
+      var changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+          range.endStart(node.rightParenthesis, body),
+          ' {$eol$indent',
+        );
+        builder.addSimpleInsertion(body.end, '$eol$prefix}');
+      });
+      return changeBuilder;
+    }
+
+    var statement = this.node.thisOrAncestorOfType<Statement>();
+    var parent = statement?.parent;
+
+    if (statement is DoStatement) {
+      return doStatement(statement);
+    } else if (parent is DoStatement) {
+      return doStatement(parent);
+    } else if (statement is ForStatement) {
+      return forStatement(statement);
+    } else if (parent is ForStatement) {
+      return forStatement(parent);
+    } else if (statement is IfStatement) {
+      if (statement.elseKeyword != null &&
+          range.token(statement.elseKeyword).contains(selectionOffset)) {
+        return ifStatement(statement, statement.elseStatement);
+      } else {
+        return ifStatement(statement, null);
+      }
+    } else if (parent is IfStatement) {
+      return ifStatement(parent, statement);
+    } else if (statement is WhileStatement) {
+      return whileStatement(statement);
+    } else if (parent is WhileStatement) {
+      return whileStatement(parent);
+    }
+    return null;
+  }
+
+  @protected
+  bool setupCompute() {
+    final locator = NodeLocator(selectionOffset, selectionEnd);
+    node = locator.searchWithin(resolvedResult.unit);
+    return node != null;
+  }
+
+  /// Configures [utils] using given [target].
+  void _configureTargetLocation(Object target) {
+    utils.targetClassElement = null;
+    if (target is AstNode) {
+      ClassDeclaration targetClassDeclaration =
+          target.thisOrAncestorOfType<ClassDeclaration>();
+      if (targetClassDeclaration != null) {
+        utils.targetClassElement = targetClassDeclaration.declaredElement;
+      }
+    }
+  }
+
+  DartChangeBuilder _newDartChangeBuilder() =>
+      DartChangeBuilderImpl.forWorkspace(workspace);
+
+  /// This method does nothing, but we invoke it in places where Dart VM
+  /// coverage agent fails to provide coverage information - such as almost
+  /// all "return" statements.
+  ///
+  /// https://code.google.com/p/dart/issues/detail?id=19912
+  static void _coverageMarker() {}
+}
+
+/// A visitor that can be used to find references to a parameter.
+class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
+  /// The parameter for which references are being sought, or `null` if we are
+  /// just accumulating a list of referenced names.
+  final ParameterElement parameter;
+
+  /// A list of the simple identifiers that reference the [parameter].
+  final List<SimpleIdentifier> references = <SimpleIdentifier>[];
+
+  /// A collection of the names of other simple identifiers that were found. We
+  /// need to know these in order to ensure that the selected loop variable does
+  /// not hide a name from an enclosing scope that is already being referenced.
+  final Set<String> otherNames = new Set<String>();
+
+  /// Initialize a newly created finder to find references to the [parameter].
+  _ParameterReferenceFinder(this.parameter) : assert(parameter != null);
+
+  /// Return `true` if the parameter is unreferenced in the nodes that have been
+  /// visited.
+  bool get isParameterUnreferenced => references.isEmpty;
+
+  /// Return `true` is the given name (assumed to be different than the name of
+  /// the parameter) is references in the nodes that have been visited.
+  bool referencesName(String name) => otherNames.contains(name);
+
+  /// Replace all of the references to the parameter in the given [source] with
+  /// the [newName]. The [offset] is the offset of the first character of the
+  /// [source] relative to the start of the file.
+  String replaceName(String source, String newName, int offset) {
+    int oldLength = parameter.name.length;
+    for (int i = references.length - 1; i >= 0; i--) {
+      int oldOffset = references[i].offset - offset;
+      source = source.replaceRange(oldOffset, oldOffset + oldLength, newName);
+    }
+    return source;
+  }
+
+  @override
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.staticElement == parameter) {
+      references.add(node);
+    } else if (!node.isQualified) {
+      // Only non-prefixed identifiers can be hidden.
+      otherNames.add(node.name);
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index adfc446..ff70d93 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -4,7 +4,7 @@
 
 import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/error/codes.dart';
@@ -16,8 +16,6 @@
 bool hasFix(ErrorCode errorCode) =>
     errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
     errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
-    errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
-    errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
     errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
     errorCode ==
         StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
@@ -32,7 +30,6 @@
             .NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
     errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
     errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
-    errorCode == StaticWarningCode.UNDEFINED_CLASS ||
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
     errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
@@ -141,6 +138,10 @@
   static const ADD_EXPLICIT_CAST = const FixKind(
       'ADD_EXPLICIT_CAST', 50, "Add cast",
       appliedTogetherMessage: "Add all casts in file");
+  static const ADD_CONST =
+      const FixKind('ADD_CONST', 50, "Add 'const' modifier");
+  static const ADD_CURLY_BRACES =
+      const FixKind('ADD_CURLY_BRACES', 50, "Add curly braces");
   static const ADD_FIELD_FORMAL_PARAMETERS = const FixKind(
       'ADD_FIELD_FORMAL_PARAMETERS', 70, "Add final field formal parameters");
   static const ADD_MISSING_ENUM_CASE_CLAUSES = const FixKind(
@@ -167,6 +168,8 @@
       'ADD_SUPER_CONSTRUCTOR_INVOCATION',
       50,
       "Add super constructor {0} invocation");
+  static const ADD_TYPE_ANNOTATION =
+      const FixKind('ADD_TYPE_ANNOTATION', 50, "Add type annotation");
   static const CHANGE_ARGUMENT_NAME =
       const FixKind('CHANGE_ARGUMENT_NAME', 60, "Change to '{0}'");
   static const CHANGE_TO = const FixKind('CHANGE_TO', 51, "Change to '{0}'");
@@ -182,8 +185,20 @@
       const FixKind('CONVERT_FLUTTER_CHILD', 50, "Convert to children:");
   static const CONVERT_FLUTTER_CHILDREN =
       const FixKind('CONVERT_FLUTTER_CHILDREN', 50, "Convert to child:");
+  static const CONVERT_INTO_EXPRESSION_BODY = const FixKind(
+      'CONVERT_INTO_EXPRESSION_BODY', 50, "Convert to expression body");
+  static const CONVERT_TO_FOR_ELEMENT =
+      const FixKind('CONVERT_TO_FOR_ELEMENT', 50, "Convert to a 'for' element");
+  static const CONVERT_TO_IF_ELEMENT =
+      const FixKind('CONVERT_TO_IF_ELEMENT', 50, "Convert to an 'if' element");
+  static const CONVERT_TO_INT_LITERAL =
+      const FixKind('CONVERT_TO_INT_LITERAL', 50, "Convert to an int literal");
+  static const CONVERT_TO_LINE_COMMENT = const FixKind(
+      'CONVERT_TO_LINE_COMMENT', 50, "Convert to line documentation comment");
   static const CONVERT_TO_NAMED_ARGUMENTS = const FixKind(
       'CONVERT_TO_NAMED_ARGUMENTS', 50, "Convert to named arguments");
+  static const CONVERT_TO_NULL_AWARE =
+      const FixKind('CONVERT_TO_NULL_AWARE', 50, "Convert to use '?.'");
   static const CREATE_CLASS =
       const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
   static const CREATE_CONSTRUCTOR =
@@ -212,6 +227,8 @@
       const FixKind('CREATE_MIXIN', 50, "Create mixin '{0}'");
   static const CREATE_NO_SUCH_METHOD = const FixKind(
       'CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
+  static const CREATE_SETTER =
+      const FixKind('CREATE_SETTER', 50, "Create setter '{0}'");
   static const EXTEND_CLASS_FOR_MIXIN =
       const FixKind('EXTEND_CLASS_FOR_MIXIN', 50, "Extend the class '{0}'");
   static const IMPORT_ASYNC =
@@ -239,6 +256,8 @@
       'MOVE_TYPE_ARGUMENTS_TO_CLASS',
       50,
       "Move type arguments to after class name");
+  static const MAKE_VARIABLE_NOT_FINAL = const FixKind(
+      'MAKE_VARIABLE_NOT_FINAL', 50, "Make variable '{0}' not final");
   static const REMOVE_ANNOTATION =
       const FixKind('REMOVE_ANNOTATION', 50, "Remove the '{0}' annotation");
   static const REMOVE_AWAIT = const FixKind('REMOVE_AWAIT', 50, "Remove await");
@@ -301,6 +320,8 @@
       const FixKind('REPLACE_COLON_WITH_EQUALS', 50, "Replace ':' with '='");
   static const REPLACE_FINAL_WITH_CONST = const FixKind(
       'REPLACE_FINAL_WITH_CONST', 50, "Replace 'final' with 'const'");
+  static const REPLACE_NEW_WITH_CONST =
+      const FixKind('REPLACE_NEW_WITH_CONST', 50, "Replace 'new' with 'const'");
   static const REPLACE_NULL_WITH_CLOSURE = const FixKind(
       'REPLACE_NULL_WITH_CLOSURE', 50, "Replace 'null' with a closure");
   static const REPLACE_RETURN_TYPE_FUTURE = const FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart b/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
index 9169ba1..5c51d43 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
@@ -35,7 +35,7 @@
 /// Kind of a top-level declaration.
 ///
 /// We don't need it to be precise, just enough to support quick fixes.
-enum TopLevelDeclarationKind { type, function, variable }
+enum TopLevelDeclarationKind { type, extension, function, variable }
 
 class TopLevelDeclarationsProvider {
   final DeclarationsTracker tracker;
@@ -94,6 +94,9 @@
       case DeclarationKind.MIXIN:
         return TopLevelDeclarationKind.type;
         break;
+      case DeclarationKind.EXTENSION:
+        return TopLevelDeclarationKind.extension;
+        break;
       case DeclarationKind.FUNCTION:
         return TopLevelDeclarationKind.function;
         break;
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 d2cd3f5..0a857ce 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -9,18 +9,17 @@
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/utilities.dart';
+import 'package:analysis_server/src/services/correction/base_processor.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/levenshtein.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
-import 'package:analysis_server/src/utilities/flutter.dart';
-import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/precedence.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -63,8 +62,6 @@
 class DartFixContributor implements FixContributor {
   @override
   Future<List<Fix>> computeFixes(DartFixContext context) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     try {
       FixProcessor processor = new FixProcessor(context);
       List<Fix> fixes = await processor.compute();
@@ -77,8 +74,6 @@
 
   Future<List<Fix>> _computeFixAllFixes(
       DartFixContext context, List<Fix> fixes) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     final analysisError = context.error;
     final allAnalysisErrors = context.resolveResult.errors.toList();
 
@@ -165,21 +160,15 @@
 /**
  * The computer for Dart fixes.
  */
-class FixProcessor {
+class FixProcessor extends BaseProcessor {
   static const int MAX_LEVENSHTEIN_DISTANCE = 3;
 
   final DartFixContext context;
   final ResourceProvider resourceProvider;
-  final AnalysisSession session;
-  final AnalysisSessionHelper sessionHelper;
-  final TypeProvider typeProvider;
   final TypeSystem typeSystem;
 
-  final String file;
   final LibraryElement unitLibraryElement;
   final CompilationUnit unit;
-  final CorrectionUtils utils;
-  final Flutter flutter;
 
   final AnalysisError error;
   final int errorOffset;
@@ -187,31 +176,23 @@
 
   final List<Fix> fixes = <Fix>[];
 
-  AstNode node;
   AstNode coveredNode;
 
   FixProcessor(this.context)
       : resourceProvider = context.resolveResult.session.resourceProvider,
-        session = context.resolveResult.session,
-        sessionHelper = AnalysisSessionHelper(context.resolveResult.session),
-        typeProvider = context.resolveResult.typeProvider,
         typeSystem = context.resolveResult.typeSystem,
-        file = context.resolveResult.path,
         unitLibraryElement = context.resolveResult.libraryElement,
         unit = context.resolveResult.unit,
-        utils = CorrectionUtils(context.resolveResult),
-        flutter = Flutter.of(context.resolveResult),
         error = context.error,
         errorOffset = context.error.offset,
-        errorLength = context.error.length;
+        errorLength = context.error.length,
+        super(
+          resolvedResult: context.resolveResult,
+          workspace: context.workspace,
+        );
 
   DartType get coreTypeBool => _getCoreType('bool');
 
-  /**
-   * Returns the EOL to use for this [CompilationUnit].
-   */
-  String get eol => utils.endOfLine;
-
   Future<List<Fix>> compute() async {
     node = new NodeLocator2(errorOffset).searchWithin(unit);
     coveredNode = new NodeLocator2(errorOffset, errorOffset + errorLength - 1)
@@ -316,7 +297,9 @@
     if (errorCode == HintCode.INVALID_FACTORY_ANNOTATION ||
         errorCode == HintCode.INVALID_IMMUTABLE_ANNOTATION ||
         errorCode == HintCode.INVALID_LITERAL_ANNOTATION ||
-        errorCode == HintCode.INVALID_REQUIRED_PARAM ||
+        errorCode == HintCode.INVALID_REQUIRED_NAMED_PARAM ||
+        errorCode == HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM ||
+        errorCode == HintCode.INVALID_REQUIRED_POSITIONAL_PARAM ||
         errorCode == HintCode.INVALID_SEALED_ANNOTATION) {
       await _addFix_removeAnnotation();
     }
@@ -414,15 +397,15 @@
     if (errorCode == StaticWarningCode.ASSIGNMENT_TO_FINAL) {
       await _addFix_makeFieldNotFinal();
     }
+    if (errorCode == StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL) {
+      await _addFix_makeVariableNotFinal();
+    }
     if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
       await _addFix_makeEnclosingClassAbstract();
     }
     if (errorCode == CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS ||
-        errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
         errorCode ==
-            CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
-        errorCode ==
-            StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
+            CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
       await _addFix_createConstructor_insteadOfSyntheticDefault();
       await _addFix_addMissingParameter();
     }
@@ -452,17 +435,14 @@
     if (errorCode == CompileTimeErrorCode.UNDEFINED_CLASS ||
         errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
         errorCode == StaticWarningCode.NOT_A_TYPE ||
-        errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
-        errorCode == StaticWarningCode.UNDEFINED_CLASS) {
+        errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME) {
       await _addFix_importLibrary_withType();
       await _addFix_createClass();
       await _addFix_createMixin();
       await _addFix_undefinedClass_useSimilar();
     }
     if (errorCode ==
-            CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
-        errorCode ==
-            StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
+        CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
       await _addFix_convertToNamedArgument();
     }
     if (errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED) {
@@ -481,13 +461,14 @@
       await _addFix_createGetter();
       await _addFix_createFunction_forFunctionType();
       await _addFix_createMixin();
+      await _addFix_createSetter();
       await _addFix_importLibrary_withType();
+      await _addFix_importLibrary_withExtension();
       await _addFix_importLibrary_withFunction();
       await _addFix_importLibrary_withTopLevelVariable();
       await _addFix_createLocalVariable();
     }
-    if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER ||
-        errorCode == StaticWarningCode.UNDEFINED_NAMED_PARAMETER) {
+    if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER) {
       await _addFix_addMissingParameterNamed();
       await _addFix_changeArgumentName();
     }
@@ -515,6 +496,7 @@
     }
     if (errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION) {
       await _addFix_createClass();
+      await _addFix_importLibrary_withExtension();
       await _addFix_importLibrary_withFunction();
       await _addFix_importLibrary_withType();
       await _addFix_undefinedFunction_useSimilar();
@@ -533,20 +515,32 @@
       await _addFix_importLibrary_withTopLevelVariable();
       await _addFix_importLibrary_withType();
     }
+    if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER) {
+      await _addFix_undefinedClassAccessor_useSimilar();
+      await _addFix_createGetter();
+    }
     if (errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) {
       await _addFix_createClass();
       await _addFix_importLibrary_withFunction();
       await _addFix_importLibrary_withType();
       await _addFix_undefinedMethod_useSimilar();
-      await _addFix_undefinedMethod_create();
+      await _addFix_createMethod();
       await _addFix_undefinedFunction_create();
     }
+    if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD) {
+      await _addFix_undefinedMethod_useSimilar();
+      await _addFix_createMethod();
+    }
     if (errorCode == StaticTypeWarningCode.UNDEFINED_SETTER) {
       await _addFix_undefinedClassAccessor_useSimilar();
       await _addFix_createField();
+      await _addFix_createSetter();
     }
-    if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER ||
-        errorCode == StaticWarningCode.UNDEFINED_NAMED_PARAMETER) {
+    if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER) {
+      await _addFix_undefinedClassAccessor_useSimilar();
+      await _addFix_createSetter();
+    }
+    if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER) {
       await _addFix_convertFlutterChild();
       await _addFix_convertFlutterChildren();
     }
@@ -572,6 +566,10 @@
     // lints
     if (errorCode is LintCode) {
       String name = errorCode.name;
+      if (name == LintNames.always_specify_types ||
+          name == LintNames.type_annotate_public_apis) {
+        await _addFix_addTypeAnnotation();
+      }
       if (name == LintNames.always_require_non_null_named_parameters) {
         await _addFix_addRequiredAnnotation();
       }
@@ -596,6 +594,9 @@
       if (name == LintNames.await_only_futures) {
         await _addFix_removeAwait();
       }
+      if (name == LintNames.curly_braces_in_flow_control_structures) {
+        await _addFix_addCurlyBraces();
+      }
       if (name == LintNames.empty_catches) {
         await _addFix_removeEmptyCatch();
       }
@@ -620,6 +621,12 @@
       if (errorCode.name == LintNames.prefer_const_declarations) {
         await _addFix_replaceFinalWithConst();
       }
+      if (errorCode.name == LintNames.prefer_expression_function_bodies) {
+        await _addFix_convertToExpressionBody();
+      }
+      if (errorCode.name == LintNames.prefer_for_elements_to_map_fromIterable) {
+        await _addFix_convertMapFromIterableToForLiteral();
+      }
       if (errorCode.name == LintNames.prefer_equal_for_default_values) {
         await _addFix_replaceColonWithEquals();
       }
@@ -629,12 +636,29 @@
       if (name == LintNames.prefer_final_locals) {
         await _addFix_makeVariableFinal();
       }
+      if (errorCode.name ==
+          LintNames.prefer_if_elements_to_conditional_expressions) {
+        await _addFix_convertConditionalToIfElement();
+      }
+      if (name == LintNames.prefer_int_literals) {
+        await _addFix_convertToIntLiteral();
+      }
       if (name == LintNames.prefer_is_empty) {
         await _addFix_replaceWithIsEmpty();
       }
       if (name == LintNames.prefer_is_not_empty) {
         await _addFix_isNotEmpty();
       }
+      if (errorCode.name == LintNames.prefer_const_constructors) {
+        await _addFix_addConst();
+        await _addFix_replaceNewWithConst();
+      }
+      if (name == LintNames.prefer_null_aware_operators) {
+        await _addFix_convertToNullAware();
+      }
+      if (errorCode.name == LintNames.slash_for_doc_comments) {
+        await _addFix_convertDocumentationIntoLine();
+      }
       if (name == LintNames.type_init_formals) {
         await _addFix_removeTypeAnnotation();
       }
@@ -674,8 +698,6 @@
   }
 
   Future<void> _addFix_addAsync() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     FunctionBody body = node.thisOrAncestorOfType<FunctionBody>();
     if (body != null && body.keyword == null) {
       TypeProvider typeProvider = this.typeProvider;
@@ -695,9 +717,33 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.ADD_AWAIT);
   }
 
+  Future<void> _addFix_addConst() async {
+    var node = coveredNode;
+    if (node is ConstructorName) {
+      node = node.parent;
+    }
+    if (node is InstanceCreationExpression) {
+      if ((node as InstanceCreationExpression).keyword == null) {
+        final changeBuilder = _newDartChangeBuilder();
+        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+          builder.addSimpleInsertion(node.offset, 'const ');
+        });
+        _addFixFromBuilder(changeBuilder, DartFixKind.ADD_CONST);
+      }
+    }
+  }
+
+  Future<void> _addFix_addCurlyBraces() async {
+    final changeBuilder = await createBuilder_useCurlyBraces();
+    _addFixFromBuilder(changeBuilder, DartFixKind.ADD_CURLY_BRACES);
+  }
+
+  Future<void> _addFix_convertToNullAware() async {
+    final changeBuilder = await createBuilder_convertToNullAware();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
+  }
+
   Future<void> _addFix_addExplicitCast() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (coveredNode is! Expression) {
       return;
     }
@@ -860,8 +906,6 @@
   }
 
   Future<void> _addFix_addMissingParameter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // The error is reported on ArgumentList.
     if (node is! ArgumentList) {
       return;
@@ -884,8 +928,6 @@
 
     Future<void> addParameter(
         FixKind kind, int offset, String prefix, String suffix) async {
-      // TODO(brianwilkerson) Determine whether this await is necessary.
-      await null;
       if (offset != null) {
         var changeBuilder = _newDartChangeBuilder();
         await changeBuilder.addFileEdit(context.file, (builder) {
@@ -990,8 +1032,6 @@
   }
 
   Future<void> _addFix_addMissingRequiredArgument() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     InstanceCreationExpression creation;
     Element targetElement;
     ArgumentList argumentList;
@@ -1062,8 +1102,6 @@
   }
 
   Future<void> _addFix_addOverrideAnnotation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     ClassMember member = node.thisOrAncestorOfType<ClassMember>();
     if (member == null) {
       return;
@@ -1089,8 +1127,6 @@
   }
 
   Future<void> _addFix_addRequiredAnnotation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addSimpleInsertion(node.parent.offset, '@required ');
@@ -1099,8 +1135,6 @@
   }
 
   Future<void> _addFix_addStatic() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     FieldDeclaration declaration =
         node.thisOrAncestorOfType<FieldDeclaration>();
     var changeBuilder = _newDartChangeBuilder();
@@ -1110,9 +1144,20 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.ADD_STATIC);
   }
 
+  Future<void> _addFix_addTypeAnnotation() async {
+    var changeBuilder =
+        await createBuilder_addTypeAnnotation_DeclaredIdentifier();
+    _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+
+    changeBuilder =
+        await createBuilder_addTypeAnnotation_SimpleFormalParameter();
+    _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+
+    changeBuilder = await createBuilder_addTypeAnnotation_VariableDeclaration();
+    _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+  }
+
   Future<void> _addFix_boolInsteadOfBoolean() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addSimpleReplacement(range.error(error), 'bool');
@@ -1121,8 +1166,6 @@
   }
 
   Future<void> _addFix_canBeNullAfterNullAware() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = coveredNode;
     if (node is Expression) {
       var changeBuilder = _newDartChangeBuilder();
@@ -1212,8 +1255,6 @@
   }
 
   Future<void> _addFix_changeTypeAnnotation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode declaration = coveredNode.parent;
     if (declaration is VariableDeclaration &&
         declaration.initializer == coveredNode) {
@@ -1234,19 +1275,26 @@
               });
             });
             _addFixFromBuilder(
-                changeBuilder, DartFixKind.CHANGE_TYPE_ANNOTATION, args: [
-              resolutionMap.typeForTypeName(typeNode),
-              newType.displayName
-            ]);
+                changeBuilder, DartFixKind.CHANGE_TYPE_ANNOTATION,
+                args: [typeNode.type, newType.displayName]);
           }
         }
       }
     }
   }
 
+  Future<void> _addFix_convertConditionalToIfElement() async {
+    final changeBuilder =
+        await createBuilder_convertConditionalExpressionToIfElement();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_IF_ELEMENT);
+  }
+
+  Future<void> _addFix_convertDocumentationIntoLine() async {
+    final changeBuilder = await createBuilder_convertDocumentationIntoLine();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_LINE_COMMENT);
+  }
+
   Future<void> _addFix_convertFlutterChild() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     NamedExpression named = flutter.findNamedExpression(node, 'child');
     if (named == null) {
       return;
@@ -1287,8 +1335,6 @@
   }
 
   Future<void> _addFix_convertFlutterChildren() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is SimpleIdentifier &&
         node.name == 'children' &&
@@ -1316,27 +1362,44 @@
     }
   }
 
+  Future<void> _addFix_convertMapFromIterableToForLiteral() async {
+    final changeBuilder =
+        await createBuilder_convertMapFromIterableToForLiteral();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_FOR_ELEMENT);
+  }
+
+  Future<void> _addFix_convertToExpressionBody() async {
+    final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_INTO_EXPRESSION_BODY);
+  }
+
+  Future<void> _addFix_convertToIntLiteral() async {
+    final changeBuilder = await createBuilder_convertToIntLiteral();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_INT_LITERAL);
+  }
+
   Future<void> _addFix_convertToNamedArgument() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var argumentList = this.node;
     if (argumentList is ArgumentList) {
-      // Prepare ExecutableElement.
-      ExecutableElement executable;
+      // Prepare parameters.
+      List<ParameterElement> parameters;
       var parent = argumentList.parent;
       if (parent is InstanceCreationExpression) {
-        executable = parent.staticElement;
+        parameters = parent.staticElement?.parameters;
       } else if (parent is MethodInvocation) {
-        executable = parent.methodName.staticElement;
+        var invokeType = parent.staticInvokeType;
+        if (invokeType is FunctionType) {
+          parameters = invokeType.parameters;
+        }
       }
-      if (executable == null) {
+      if (parameters == null) {
         return;
       }
 
       // Prepare named parameters.
       int numberOfPositionalParameters = 0;
       var namedParameters = <ParameterElement>[];
-      for (var parameter in executable.parameters) {
+      for (var parameter in parameters) {
         if (parameter.isNamed) {
           namedParameters.add(parameter);
         } else {
@@ -1387,8 +1450,6 @@
   }
 
   Future<void> _addFix_createClass() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     Element prefixElement = null;
     String name = null;
     SimpleIdentifier nameNode;
@@ -1473,8 +1534,6 @@
    * class has uninitialized final fields.
    */
   Future<void> _addFix_createConstructor_forUninitializedFinalFields() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier || node.parent is! VariableDeclaration) {
       return;
     }
@@ -1551,8 +1610,6 @@
   }
 
   Future<void> _addFix_createConstructor_insteadOfSyntheticDefault() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! ArgumentList) {
       return;
     }
@@ -1601,8 +1658,6 @@
   }
 
   Future<void> _addFix_createConstructor_named() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     SimpleIdentifier name = null;
     ConstructorName constructorName = null;
     InstanceCreationExpression instanceCreation = null;
@@ -1666,8 +1721,6 @@
   }
 
   Future<void> _addFix_createConstructorSuperExplicit() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node.parent is! ConstructorDeclaration ||
         node.parent.parent is! ClassDeclaration) {
       return;
@@ -1737,8 +1790,6 @@
   }
 
   Future<void> _addFix_createConstructorSuperImplicit() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     ClassDeclaration targetClassNode =
         node.thisOrAncestorOfType<ClassDeclaration>();
     ClassElement targetClassElement = targetClassNode.declaredElement;
@@ -1807,8 +1858,6 @@
   }
 
   Future<void> _addFix_createField() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier) {
       return;
     }
@@ -1886,8 +1935,6 @@
   }
 
   Future<void> _addFix_createField_initializingFormal() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     //
     // Ensure that we are in an initializing formal parameter.
     //
@@ -1922,8 +1969,6 @@
   }
 
   Future<void> _addFix_createFunction_forFunctionType() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       SimpleIdentifier nameNode = node as SimpleIdentifier;
       // prepare argument expression (to get parameter)
@@ -1972,8 +2017,6 @@
   }
 
   Future<void> _addFix_createGetter() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier) {
       return;
     }
@@ -1982,7 +2025,7 @@
     if (!nameNode.inGetterContext()) {
       return;
     }
-    // prepare target Expression
+    // prepare target
     Expression target;
     {
       AstNode nameParent = nameNode.parent;
@@ -1992,16 +2035,22 @@
         target = nameParent.realTarget;
       }
     }
-    // prepare target ClassElement
+    // prepare target element
     bool staticModifier = false;
-    ClassElement targetClassElement;
-    if (target != null) {
+    Element targetElement;
+    if (target is ExtensionOverride) {
+      targetElement = target.staticElement;
+    } else if (target is Identifier &&
+        target.staticElement is ExtensionElement) {
+      targetElement = target.staticElement;
+      staticModifier = true;
+    } else if (target != null) {
       // prepare target interface type
       DartType targetType = target.staticType;
       if (targetType is! InterfaceType) {
         return;
       }
-      targetClassElement = targetType.element;
+      targetElement = targetType.element;
       // maybe static
       if (target is Identifier) {
         Identifier targetIdentifier = target;
@@ -2009,29 +2058,30 @@
         staticModifier = targetElement?.kind == ElementKind.CLASS;
       }
     } else {
-      targetClassElement = getEnclosingClassElement(node);
-      if (targetClassElement == null) {
+      targetElement =
+          getEnclosingClassElement(node) ?? getEnclosingExtensionElement(node);
+      if (targetElement == null) {
         return;
       }
       staticModifier = _inStaticContext();
     }
-    if (targetClassElement.librarySource.isInSystemLibrary) {
+    if (targetElement.librarySource.isInSystemLibrary) {
       return;
     }
-    utils.targetClassElement = targetClassElement;
-    // prepare target ClassOrMixinDeclaration
+    // prepare target declaration
     var targetDeclarationResult =
-        await sessionHelper.getElementDeclaration(targetClassElement);
-    if (targetDeclarationResult.node is! ClassOrMixinDeclaration) {
+        await sessionHelper.getElementDeclaration(targetElement);
+    if (targetDeclarationResult.node is! ClassOrMixinDeclaration &&
+        targetDeclarationResult.node is! ExtensionDeclaration) {
       return;
     }
-    ClassOrMixinDeclaration targetNode = targetDeclarationResult.node;
+    CompilationUnitMember targetNode = targetDeclarationResult.node;
     // prepare location
     ClassMemberLocation targetLocation =
         CorrectionUtils(targetDeclarationResult.resolvedUnit)
             .prepareNewGetterLocation(targetNode);
     // build method source
-    Source targetSource = targetClassElement.source;
+    Source targetSource = targetElement.source;
     String targetFile = targetSource.fullName;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
@@ -2051,8 +2101,6 @@
   }
 
   Future<void> _addFix_createImportUri() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // TODO(brianwilkerson) Generalize this to allow other valid string literals.
     // TODO(brianwilkerson) Support the case where the node's parent is a Configuration.
     if (node is SimpleStringLiteral && node.parent is ImportDirective) {
@@ -2076,8 +2124,6 @@
   }
 
   Future<void> _addFix_createLocalVariable() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier) {
       return;
     }
@@ -2124,9 +2170,104 @@
         args: [name]);
   }
 
+  Future<void> _addFix_createMethod() async {
+    if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+      return;
+    }
+    String name = (node as SimpleIdentifier).name;
+    MethodInvocation invocation = node.parent as MethodInvocation;
+    // prepare environment
+    Element targetElement;
+    bool staticModifier = false;
+
+    CompilationUnitMember targetNode;
+    Expression target = invocation.realTarget;
+    CorrectionUtils utils = this.utils;
+    if (target is ExtensionOverride) {
+      targetElement = target.staticElement;
+      targetNode = await _getExtensionDeclaration(targetElement);
+      if (targetNode == null) {
+        return;
+      }
+    } else if (target is Identifier &&
+        target.staticElement is ExtensionElement) {
+      targetElement = target.staticElement;
+      targetNode = await _getExtensionDeclaration(targetElement);
+      if (targetNode == null) {
+        return;
+      }
+      staticModifier = true;
+    } else if (target == null) {
+      targetElement = unit.declaredElement;
+      ClassMember enclosingMember = node.thisOrAncestorOfType<ClassMember>();
+      if (enclosingMember == null) {
+        // If the undefined identifier isn't inside a class member, then it
+        // doesn't make sense to create a method.
+        return;
+      }
+      targetNode = enclosingMember.parent;
+      staticModifier = _inStaticContext();
+    } else {
+      // prepare target interface type
+      DartType targetType = target.staticType;
+      if (targetType is! InterfaceType) {
+        return;
+      }
+      ClassElement targetClassElement = targetType.element as ClassElement;
+      if (targetClassElement.librarySource.isInSystemLibrary) {
+        return;
+      }
+      targetElement = targetClassElement;
+      // prepare target ClassDeclaration
+      targetNode = await _getClassDeclaration(targetClassElement);
+      if (targetNode == null) {
+        return;
+      }
+      // maybe static
+      if (target is Identifier) {
+        staticModifier = target.staticElement.kind == ElementKind.CLASS;
+      }
+      // use different utils
+      var targetPath = targetClassElement.source.fullName;
+      var targetResolveResult = await session.getResolvedUnit(targetPath);
+      utils = CorrectionUtils(targetResolveResult);
+    }
+    ClassMemberLocation targetLocation =
+        utils.prepareNewMethodLocation(targetNode);
+    String targetFile = targetElement.source.fullName;
+    // build method source
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
+      builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
+        builder.write(targetLocation.prefix);
+        // maybe "static"
+        if (staticModifier) {
+          builder.write('static ');
+        }
+        // append return type
+        {
+          DartType type = _inferUndefinedExpressionType(invocation);
+          if (builder.writeType(type, groupName: 'RETURN_TYPE')) {
+            builder.write(' ');
+          }
+        }
+        // append name
+        builder.addLinkedEdit('NAME', (DartLinkedEditBuilder builder) {
+          builder.write(name);
+        });
+        builder.write('(');
+        builder.writeParametersMatchingArguments(invocation.argumentList);
+        builder.write(') {}');
+        builder.write(targetLocation.suffix);
+      });
+      if (targetFile == file) {
+        builder.addLinkedPosition(range.node(node), 'NAME');
+      }
+    });
+    _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD, args: [name]);
+  }
+
   Future<void> _addFix_createMissingOverrides() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node.parent is! ClassDeclaration) {
       return;
     }
@@ -2294,8 +2435,6 @@
   }
 
   Future<void> _addFix_createNoSuchMethod() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node.parent is! ClassDeclaration) {
       return;
     }
@@ -2322,8 +2461,6 @@
   }
 
   Future<void> _addFix_createPartUri() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // TODO(brianwilkerson) Generalize this to allow other valid string literals.
     if (node is SimpleStringLiteral && node.parent is PartDirective) {
       PartDirective partDirective = node.parent;
@@ -2342,6 +2479,91 @@
     }
   }
 
+  Future<void> _addFix_createSetter() async {
+    if (node is! SimpleIdentifier) {
+      return;
+    }
+    SimpleIdentifier nameNode = node;
+    if (!nameNode.inSetterContext()) {
+      return;
+    }
+    // prepare target
+    Expression target;
+    {
+      AstNode nameParent = nameNode.parent;
+      if (nameParent is PrefixedIdentifier) {
+        target = nameParent.prefix;
+      } else if (nameParent is PropertyAccess) {
+        target = nameParent.realTarget;
+      }
+    }
+    // prepare target element
+    bool staticModifier = false;
+    Element targetElement;
+    if (target is ExtensionOverride) {
+      targetElement = target.staticElement;
+    } else if (target is Identifier &&
+        target.staticElement is ExtensionElement) {
+      targetElement = target.staticElement;
+      staticModifier = true;
+    } else if (target != null) {
+      // prepare target interface type
+      DartType targetType = target.staticType;
+      if (targetType is! InterfaceType) {
+        return;
+      }
+      targetElement = targetType.element;
+      // maybe static
+      if (target is Identifier) {
+        Identifier targetIdentifier = target;
+        Element targetElement = targetIdentifier.staticElement;
+        staticModifier = targetElement?.kind == ElementKind.CLASS;
+      }
+    } else {
+      targetElement =
+          getEnclosingClassElement(node) ?? getEnclosingExtensionElement(node);
+      if (targetElement == null) {
+        return;
+      }
+      staticModifier = _inStaticContext();
+    }
+    if (targetElement.librarySource.isInSystemLibrary) {
+      return;
+    }
+    // prepare target declaration
+    var targetDeclarationResult =
+        await sessionHelper.getElementDeclaration(targetElement);
+    if (targetDeclarationResult.node is! ClassOrMixinDeclaration &&
+        targetDeclarationResult.node is! ExtensionDeclaration) {
+      return;
+    }
+    CompilationUnitMember targetNode = targetDeclarationResult.node;
+    // prepare location
+    ClassMemberLocation targetLocation = CorrectionUtils(
+            targetDeclarationResult.resolvedUnit)
+        .prepareNewGetterLocation(targetNode); // Rename to "AccessorLocation"
+    // build method source
+    Source targetSource = targetElement.source;
+    String targetFile = targetSource.fullName;
+    String name = nameNode.name;
+    var changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
+      builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
+        Expression parameterTypeNode = climbPropertyAccess(nameNode);
+        DartType parameterType =
+            _inferUndefinedExpressionType(parameterTypeNode);
+        builder.write(targetLocation.prefix);
+        builder.writeSetterDeclaration(name,
+            isStatic: staticModifier,
+            nameGroupName: 'NAME',
+            parameterType: parameterType,
+            parameterTypeGroupName: 'TYPE');
+        builder.write(targetLocation.suffix);
+      });
+    });
+    _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_SETTER, args: [name]);
+  }
+
   Future<void> _addFix_extendClassForMixin() async {
     ClassDeclaration declaration =
         node.thisOrAncestorOfType<ClassDeclaration>();
@@ -2364,8 +2586,6 @@
   }
 
   Future<void> _addFix_illegalAsyncReturnType() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare the existing type
     TypeAnnotation typeName = node.thisOrAncestorOfType<TypeAnnotation>();
     TypeProvider typeProvider = this.typeProvider;
@@ -2383,8 +2603,6 @@
 
   Future<void> _addFix_importLibrary(FixKind kind, Uri library,
       [String relativeURI = null]) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     String uriText;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -2407,8 +2625,6 @@
       String name,
       List<ElementKind> elementKinds,
       List<TopLevelDeclarationKind> kinds2) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // ignore if private
     if (name.startsWith('_')) {
       return;
@@ -2508,9 +2724,15 @@
     }
   }
 
+  Future<void> _addFix_importLibrary_withExtension() async {
+    String extensionName = (node as SimpleIdentifier).name;
+    await _addFix_importLibrary_withElement(
+        extensionName,
+        const [ElementKind.EXTENSION],
+        const [TopLevelDeclarationKind.extension]);
+  }
+
   Future<void> _addFix_importLibrary_withFunction() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       if (node.parent is MethodInvocation) {
         MethodInvocation invocation = node.parent as MethodInvocation;
@@ -2531,8 +2753,6 @@
   }
 
   Future<void> _addFix_importLibrary_withTopLevelVariable() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       String name = (node as SimpleIdentifier).name;
       await _addFix_importLibrary_withElement(
@@ -2543,8 +2763,6 @@
   }
 
   Future<void> _addFix_importLibrary_withType() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (_mayBeTypeIdentifier(node)) {
       String typeName = (node as SimpleIdentifier).name;
       await _addFix_importLibrary_withElement(
@@ -2559,8 +2777,6 @@
   }
 
   Future<void> _addFix_insertSemicolon() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (error.message.contains("';'")) {
       if (_isAwaitNode()) {
         return;
@@ -2575,8 +2791,6 @@
   }
 
   Future<void> _addFix_isNotEmpty() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! PrefixExpression) {
       return;
     }
@@ -2603,8 +2817,6 @@
   }
 
   Future<void> _addFix_isNotNull() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (coveredNode is IsExpression) {
       IsExpression isExpression = coveredNode as IsExpression;
       var changeBuilder = _newDartChangeBuilder();
@@ -2620,8 +2832,6 @@
   }
 
   Future<void> _addFix_isNull() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (coveredNode is IsExpression) {
       IsExpression isExpression = coveredNode as IsExpression;
       var changeBuilder = _newDartChangeBuilder();
@@ -2637,8 +2847,6 @@
   }
 
   Future<void> _addFix_makeEnclosingClassAbstract() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     ClassDeclaration enclosingClass =
         node.thisOrAncestorOfType<ClassDeclaration>();
     if (enclosingClass == null) {
@@ -2655,8 +2863,6 @@
   }
 
   Future<void> _addFix_makeFieldNotFinal() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is SimpleIdentifier &&
         node.staticElement is PropertyAccessorElement) {
@@ -2700,8 +2906,6 @@
   }
 
   Future<void> _addFix_makeVariableFinal() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is SimpleIdentifier && node.parent is VariableDeclaration) {
       VariableDeclaration declaration = node.parent;
@@ -2720,6 +2924,37 @@
     }
   }
 
+  Future<void> _addFix_makeVariableNotFinal() async {
+    AstNode node = this.node;
+    if (node is SimpleIdentifier &&
+        node.staticElement is LocalVariableElement) {
+      LocalVariableElement variable = node.staticElement;
+      var id = NodeLocator(variable.nameOffset).searchWithin(unit);
+      var decl = id?.parent;
+      if (decl is VariableDeclaration &&
+          decl.parent is VariableDeclarationList) {
+        VariableDeclarationList declarationList = decl.parent;
+        var keywordToken = declarationList.keyword;
+        if (declarationList.variables.length == 1 &&
+            keywordToken.keyword == Keyword.FINAL) {
+          var changeBuilder = _newDartChangeBuilder();
+          await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+            if (declarationList.type != null) {
+              builder.addDeletion(
+                  range.startStart(keywordToken, declarationList.type));
+            } else {
+              builder.addSimpleReplacement(range.token(keywordToken), 'var');
+            }
+          });
+          declarationList.variables[0].name.name;
+          var varName = declarationList.variables[0].name.name;
+          _addFixFromBuilder(changeBuilder, DartFixKind.MAKE_VARIABLE_NOT_FINAL,
+              args: [varName]);
+        }
+      }
+    }
+  }
+
   Future<void> _addFix_moveTypeArgumentsToClass() async {
     if (coveredNode is TypeArgumentList) {
       TypeArgumentList typeArguments = coveredNode;
@@ -2748,8 +2983,6 @@
   }
 
   Future<void> _addFix_nonBoolCondition_addNotNull() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addSimpleInsertion(error.offset + error.length, ' != null');
@@ -2801,8 +3034,6 @@
   }
 
   Future<void> _addFix_removeAwait() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     final awaitExpression = node;
     if (awaitExpression is AwaitExpression) {
       final awaitToken = awaitExpression.awaitKeyword;
@@ -2890,8 +3121,6 @@
   }
 
   Future<void> _addFix_removeEmptyCatch() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addDeletion(utils.getLinesRange(range.node(node.parent)));
@@ -2900,8 +3129,6 @@
   }
 
   Future<void> _addFix_removeEmptyConstructorBody() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addSimpleReplacement(
@@ -2912,8 +3139,6 @@
   }
 
   Future<void> _addFix_removeEmptyElse() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     IfStatement ifStatement = node.parent;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -2924,8 +3149,6 @@
   }
 
   Future<void> _addFix_removeEmptyStatement() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     EmptyStatement emptyStatement = node;
     if (emptyStatement.parent is Block) {
       var changeBuilder = _newDartChangeBuilder();
@@ -2947,8 +3170,6 @@
   }
 
   Future<void> _addFix_removeInitializer() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // Retrieve the linted node.
     VariableDeclaration ancestor =
         node.thisOrAncestorOfType<VariableDeclaration>();
@@ -2963,8 +3184,6 @@
   }
 
   Future<void> _addFix_removeInterpolationBraces() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is InterpolationExpression) {
       Token right = node.rightBracket;
@@ -2982,8 +3201,6 @@
   }
 
   Future<void> _addFix_removeMethodDeclaration() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     MethodDeclaration declaration =
         node.thisOrAncestorOfType<MethodDeclaration>();
     if (declaration != null) {
@@ -3070,8 +3287,6 @@
   }
 
   Future<void> _addFix_removeParameters_inGetterDeclaration() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is MethodDeclaration) {
       // Support for the analyzer error.
       MethodDeclaration method = node as MethodDeclaration;
@@ -3097,8 +3312,6 @@
   }
 
   Future<void> _addFix_removeParentheses_inGetterInvocation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier && node.parent is MethodInvocation) {
       MethodInvocation invocation = node.parent as MethodInvocation;
       if (invocation.methodName == node && invocation.target != null) {
@@ -3113,8 +3326,6 @@
   }
 
   Future<void> _addFix_removeThisExpression() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     final thisExpression = node is ThisExpression
         ? node
         : node.thisOrAncestorOfType<ThisExpression>();
@@ -3135,8 +3346,6 @@
   }
 
   Future<void> _addFix_removeTypeAnnotation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     final TypeAnnotation type = node.thisOrAncestorOfType<TypeAnnotation>();
     if (type != null) {
       var changeBuilder = _newDartChangeBuilder();
@@ -3159,8 +3368,6 @@
   }
 
   Future<void> _addFix_removeUnnecessaryCast() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (coveredNode is! AsExpression) {
       return;
     }
@@ -3177,8 +3384,6 @@
   }
 
   Future<void> _addFix_removeUnusedCatchClause() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       AstNode catchClause = node.parent;
       if (catchClause is CatchClause &&
@@ -3195,8 +3400,6 @@
   }
 
   Future<void> _addFix_removeUnusedCatchStack() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       AstNode catchClause = node.parent;
       if (catchClause is CatchClause &&
@@ -3214,8 +3417,6 @@
   }
 
   Future<void> _addFix_removeUnusedImport() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // prepare ImportDirective
     ImportDirective importDirective =
         node.thisOrAncestorOfType<ImportDirective>();
@@ -3231,8 +3432,6 @@
   }
 
   Future<void> _addFix_renameToCamelCase() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier) {
       return;
     }
@@ -3286,8 +3485,6 @@
   }
 
   Future<void> _addFix_replaceFinalWithConst() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is VariableDeclarationList) {
       var changeBuilder = _newDartChangeBuilder();
       await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -3298,6 +3495,23 @@
     }
   }
 
+  Future<void> _addFix_replaceNewWithConst() async {
+    var node = coveredNode;
+    if (node is ConstructorName) {
+      node = node.parent;
+    }
+    if (node is InstanceCreationExpression) {
+      final keyword = node.keyword;
+      if (keyword != null) {
+        final changeBuilder = _newDartChangeBuilder();
+        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+          builder.addSimpleReplacement(range.token(keyword), 'const');
+        });
+        _addFixFromBuilder(changeBuilder, DartFixKind.REPLACE_NEW_WITH_CONST);
+      }
+    }
+  }
+
   Future<void> _addFix_replaceNullWithClosure() async {
     var nodeToFix;
     var parameters = const <ParameterElement>[];
@@ -3332,8 +3546,6 @@
   }
 
   Future<void> _addFix_replaceVarWithDynamic() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
       builder.addSimpleReplacement(range.error(error), 'dynamic');
@@ -3342,8 +3554,6 @@
   }
 
   Future<void> _addFix_replaceWithConditionalAssignment() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     IfStatement ifStatement =
         node is IfStatement ? node : node.thisOrAncestorOfType<IfStatement>();
     if (ifStatement == null) {
@@ -3378,8 +3588,6 @@
   }
 
   Future<void> _addFix_replaceWithConstInstanceCreation() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (coveredNode is InstanceCreationExpression) {
       var instanceCreation = coveredNode as InstanceCreationExpression;
       var changeBuilder = _newDartChangeBuilder();
@@ -3397,8 +3605,6 @@
   }
 
   Future<void> _addFix_replaceWithIdentifier() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     final FunctionTypedFormalParameter functionTyped =
         node.thisOrAncestorOfType<FunctionTypedFormalParameter>();
     if (functionTyped != null) {
@@ -3518,16 +3724,12 @@
   }
 
   Future<void> _addFix_replaceWithTearOff() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     FunctionExpression ancestor =
         node.thisOrAncestorOfType<FunctionExpression>();
     if (ancestor == null) {
       return;
     }
     Future<void> addFixOfExpression(InvocationExpression expression) async {
-      // TODO(brianwilkerson) Determine whether this await is necessary.
-      await null;
       var changeBuilder = _newDartChangeBuilder();
       await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
         builder.addReplacement(range.node(ancestor), (DartEditBuilder builder) {
@@ -3558,8 +3760,6 @@
   }
 
   Future<void> _addFix_undefinedClass_useSimilar() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     // Prepare the optional import prefix name.
     String prefixName = null;
@@ -3609,15 +3809,14 @@
   }
 
   Future<void> _addFix_undefinedClassAccessor_useSimilar() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is SimpleIdentifier) {
       // prepare target
       Expression target = null;
       if (node.parent is PrefixedIdentifier) {
-        PrefixedIdentifier invocation = node.parent as PrefixedIdentifier;
-        target = invocation.prefix;
+        target = (node.parent as PrefixedIdentifier).prefix;
+      } else if (node.parent is PropertyAccess) {
+        target = (node.parent as PropertyAccess).target;
       }
       // find getter
       if (node.inGetterContext()) {
@@ -3640,8 +3839,6 @@
 
   Future<void> _addFix_undefinedClassMember_useSimilar(
       Expression target, ElementPredicate predicate) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier) {
       String name = (node as SimpleIdentifier).name;
       _ClosestElementFinder finder =
@@ -3653,6 +3850,11 @@
           ClassElement classElement = clazz.declaredElement;
           _updateFinderWithClassMembers(finder, classElement);
         }
+      } else if (target is ExtensionOverride) {
+        _updateFinderWithExtensionMembers(finder, target.staticElement);
+      } else if (target is Identifier &&
+          target.staticElement is ExtensionElement) {
+        _updateFinderWithExtensionMembers(finder, target.staticElement);
       } else {
         DartType type = target.staticType;
         if (type is InterfaceType) {
@@ -3662,7 +3864,7 @@
       }
       // if we have close enough element, suggest to use it
       if (finder._element != null) {
-        String closestName = finder._element.name;
+        String closestName = finder._element.displayName;
         var changeBuilder = _newDartChangeBuilder();
         await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
           builder.addSimpleReplacement(range.node(node), closestName);
@@ -3674,8 +3876,6 @@
   }
 
   Future<void> _addFix_undefinedFunction_create() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // should be the name of the invocation
     if (node is SimpleIdentifier && node.parent is MethodInvocation) {
     } else {
@@ -3723,8 +3923,6 @@
   }
 
   Future<void> _addFix_undefinedFunction_useSimilar() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     AstNode node = this.node;
     if (node is SimpleIdentifier) {
       // Prepare the optional import prefix name.
@@ -3770,98 +3968,7 @@
     }
   }
 
-  Future<void> _addFix_undefinedMethod_create() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
-      String name = (node as SimpleIdentifier).name;
-      MethodInvocation invocation = node.parent as MethodInvocation;
-      // prepare environment
-      Element targetElement;
-      bool staticModifier = false;
-
-      ClassOrMixinDeclaration targetClassNode;
-      Expression target = invocation.realTarget;
-      CorrectionUtils utils = this.utils;
-      if (target == null) {
-        targetElement = unit.declaredElement;
-        ClassMember enclosingMember = node.thisOrAncestorOfType<ClassMember>();
-        if (enclosingMember == null) {
-          // If the undefined identifier isn't inside a class member, then it
-          // doesn't make sense to create a method.
-          return;
-        }
-        targetClassNode = enclosingMember.parent;
-        utils.targetClassElement = targetClassNode.declaredElement;
-        staticModifier = _inStaticContext();
-      } else {
-        // prepare target interface type
-        DartType targetType = target.staticType;
-        if (targetType is! InterfaceType) {
-          return;
-        }
-        ClassElement targetClassElement = targetType.element as ClassElement;
-        if (targetClassElement.librarySource.isInSystemLibrary) {
-          return;
-        }
-        targetElement = targetClassElement;
-        // prepare target ClassDeclaration
-        targetClassNode = await _getClassDeclaration(targetClassElement);
-        if (targetClassNode == null) {
-          return;
-        }
-        // maybe static
-        if (target is Identifier) {
-          staticModifier =
-              resolutionMap.staticElementForIdentifier(target).kind ==
-                  ElementKind.CLASS;
-        }
-        // use different utils
-        var targetPath = targetClassElement.source.fullName;
-        var targetResolveResult = await session.getResolvedUnit(targetPath);
-        utils = CorrectionUtils(targetResolveResult);
-      }
-      ClassMemberLocation targetLocation =
-          utils.prepareNewMethodLocation(targetClassNode);
-      String targetFile = targetElement.source.fullName;
-      // build method source
-      var changeBuilder = _newDartChangeBuilder();
-      await changeBuilder.addFileEdit(targetFile,
-          (DartFileEditBuilder builder) {
-        builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
-          builder.write(targetLocation.prefix);
-          // maybe "static"
-          if (staticModifier) {
-            builder.write('static ');
-          }
-          // append return type
-          {
-            DartType type = _inferUndefinedExpressionType(invocation);
-            if (builder.writeType(type, groupName: 'RETURN_TYPE')) {
-              builder.write(' ');
-            }
-          }
-          // append name
-          builder.addLinkedEdit('NAME', (DartLinkedEditBuilder builder) {
-            builder.write(name);
-          });
-          builder.write('(');
-          builder.writeParametersMatchingArguments(invocation.argumentList);
-          builder.write(') {}');
-          builder.write(targetLocation.suffix);
-        });
-        if (targetFile == file) {
-          builder.addLinkedPosition(range.node(node), 'NAME');
-        }
-      });
-      _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD,
-          args: [name]);
-    }
-  }
-
   Future<void> _addFix_undefinedMethod_useSimilar() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node.parent is MethodInvocation) {
       MethodInvocation invocation = node.parent as MethodInvocation;
       await _addFix_undefinedClassMember_useSimilar(invocation.realTarget,
@@ -3874,8 +3981,6 @@
    * final fields.
    */
   Future<void> _addFix_updateConstructor_forUninitializedFinalFields() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is! SimpleIdentifier || node.parent is! ConstructorDeclaration) {
       return;
     }
@@ -3982,8 +4087,6 @@
   }
 
   Future<void> _addFix_useEffectiveIntegerDivision() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     for (AstNode n = node; n != null; n = n.parent) {
       if (n is MethodInvocation &&
           n.offset == errorOffset &&
@@ -4026,8 +4129,6 @@
   }
 
   Future<void> _addFix_useStaticAccess_method() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier && node.parent is MethodInvocation) {
       MethodInvocation invocation = node.parent as MethodInvocation;
       if (invocation.methodName == node) {
@@ -4039,8 +4140,6 @@
   }
 
   Future<void> _addFix_useStaticAccess_property() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     if (node is SimpleIdentifier && node.parent is PrefixedIdentifier) {
       PrefixedIdentifier prefixed = node.parent as PrefixedIdentifier;
       if (prefixed.identifier == node) {
@@ -4053,6 +4152,7 @@
 
   void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
       {List args = null, bool importsOnly = false}) {
+    if (builder == null) return;
     SourceChange change = builder.sourceChange;
     if (change.edits.isEmpty && !importsOnly) {
       return;
@@ -4075,8 +4175,6 @@
       String sourcePrefix,
       String sourceSuffix,
       Element target) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     // build method source
     var changeBuilder = _newDartChangeBuilder();
     await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
@@ -4138,8 +4236,6 @@
    */
   Future<void> _addProposal_createFunction_function(
       FunctionType functionType) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     String name = (node as SimpleIdentifier).name;
     // prepare environment
     int insertOffset = unit.end;
@@ -4167,8 +4263,6 @@
    */
   Future<void> _addProposal_createFunction_method(
       ClassElement targetClassElement, FunctionType functionType) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     String name = (node as SimpleIdentifier).name;
     // prepare environment
     Source targetSource = targetClassElement.source;
@@ -4200,9 +4294,7 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD, args: [name]);
   }
 
-  /**
-   * Returns the [ClassOrMixinDeclaration] for the given [element].
-   */
+  /// Return the class, enum or mixin declaration for the given [element].
   Future<ClassOrMixinDeclaration> _getClassDeclaration(
       ClassElement element) async {
     var result = await sessionHelper.getElementDeclaration(element);
@@ -4245,6 +4337,16 @@
     return null;
   }
 
+  /// Return the extension declaration for the given [element].
+  Future<ExtensionDeclaration> _getExtensionDeclaration(
+      ExtensionElement element) async {
+    var result = await sessionHelper.getElementDeclaration(element);
+    if (result.node is ExtensionDeclaration) {
+      return result.node;
+    }
+    return null;
+  }
+
   /**
    * Return the relative uri from the passed [library] to the given [path].
    * If the [path] is not in the LibraryElement, `null` is returned.
@@ -4516,6 +4618,13 @@
     }
   }
 
+  void _updateFinderWithExtensionMembers(
+      _ClosestElementFinder finder, ExtensionElement element) {
+    if (element != null) {
+      finder._updateList(getExtensionMembers(element));
+    }
+  }
+
   static bool _isNameOfType(String name) {
     if (name.isEmpty) {
       return false;
@@ -4563,51 +4672,6 @@
 }
 
 /**
- * An enumeration of lint names.
- */
-class LintNames {
-  static const String always_require_non_null_named_parameters =
-      'always_require_non_null_named_parameters';
-  static const String annotate_overrides = 'annotate_overrides';
-  static const String avoid_annotating_with_dynamic =
-      'avoid_annotating_with_dynamic';
-  static const String avoid_empty_else = 'avoid_empty_else';
-  static const String avoid_init_to_null = 'avoid_init_to_null';
-  static const String avoid_return_types_on_setters =
-      'avoid_return_types_on_setters';
-  static const String avoid_types_on_closure_parameters =
-      'avoid_types_on_closure_parameters';
-  static const String await_only_futures = 'await_only_futures';
-  static const String empty_catches = 'empty_catches';
-  static const String empty_constructor_bodies = 'empty_constructor_bodies';
-  static const String empty_statements = 'empty_statements';
-  static const String no_duplicate_case_values = 'no_duplicate_case_values';
-  static const String non_constant_identifier_names =
-      'non_constant_identifier_names';
-  static const String null_closures = 'null_closures';
-  static const String prefer_collection_literals = 'prefer_collection_literals';
-  static const String prefer_conditional_assignment =
-      'prefer_conditional_assignment';
-  static const String prefer_const_declarations = 'prefer_const_declarations';
-  static const String prefer_equal_for_default_values =
-      'prefer_equal_for_default_values';
-  static const String prefer_final_fields = 'prefer_final_fields';
-  static const String prefer_final_locals = 'prefer_final_locals';
-  static const String prefer_is_empty = 'prefer_is_empty';
-  static const String prefer_is_not_empty = 'prefer_is_not_empty';
-  static const String type_init_formals = 'type_init_formals';
-  static const String unawaited_futures = 'unawaited_futures';
-  static const String unnecessary_brace_in_string_interps =
-      'unnecessary_brace_in_string_interps';
-  static const String unnecessary_const = 'unnecessary_const';
-  static const String unnecessary_lambdas = 'unnecessary_lambdas';
-  static const String unnecessary_new = 'unnecessary_new';
-  static const String unnecessary_overrides = 'unnecessary_overrides';
-  static const String unnecessary_this = 'unnecessary_this';
-  static const String use_rethrow_when_possible = 'use_rethrow_when_possible';
-}
-
-/**
  * Helper for finding [Element] with name closest to the given.
  */
 class _ClosestElementFinder {
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index 878ed69..70e5683 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 
@@ -127,8 +126,7 @@
   // prepare environment
   AstNode parent = prefixNode.parent;
   CompilationUnit unit = prefixNode.thisOrAncestorOfType<CompilationUnit>();
-  LibraryElement libraryElement =
-      resolutionMap.elementDeclaredByCompilationUnit(unit).library;
+  LibraryElement libraryElement = unit.declaredElement.library;
   // prepare used element
   Element usedElement = null;
   if (parent is PrefixedIdentifier) {
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 1fcc638..4519397 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -232,18 +232,10 @@
   }
 }
 
-/**
- * If the given [AstNode] is in a [ClassOrMixinDeclaration], returns the
- * [ClassElement]. Otherwise returns `null`.
- */
-ClassElement getEnclosingClassElement(AstNode node) {
-  ClassOrMixinDeclaration enclosingClassNode =
-      node.thisOrAncestorOfType<ClassOrMixinDeclaration>();
-  if (enclosingClassNode != null) {
-    return enclosingClassNode.declaredElement;
-  }
-  return null;
-}
+/// If the given [node] is in a class, enum or mixin declaration, return the
+/// declared [ClassElement]. Otherwise return `null`.
+ClassElement getEnclosingClassElement(AstNode node) =>
+    node.thisOrAncestorOfType<ClassOrMixinDeclaration>()?.declaredElement;
 
 /**
  * Returns a class or an unit member enclosing the given [node].
@@ -301,6 +293,11 @@
   return null;
 }
 
+/// If the given [node] is in an extension, return the declared
+/// [ExtensionElement]. Otherwise return `null`.
+ExtensionElement getEnclosingExtensionElement(AstNode node) =>
+    node.thisOrAncestorOfType<ExtensionDeclaration>()?.declaredElement;
+
 /**
  * Returns [getExpressionPrecedence] for the parent of [node], or
  * ASSIGNMENT_PRECEDENCE if the parent node is a [ParenthesizedExpression].
@@ -1042,22 +1039,22 @@
   }
 
   /**
-   * @return the source of the inverted condition for the given logical expression.
+   * Return the source of the inverted condition for the given logical expression.
    */
   String invertCondition(Expression expression) =>
       _invertCondition0(expression)._source;
 
   /**
-   * Return `true` if the given [classDeclaration] has open '{' and close '}'
-   * at the same line, e.g. `class X {}`.
+   * Return `true` if the given class, mixin, enum or extension [declaration]
+   * has open '{' and close '}' on the same line, e.g. `class X {}`.
    */
-  bool isClassWithEmptyBody(ClassOrMixinDeclaration classDeclaration) {
-    return getLineThis(classDeclaration.leftBracket.offset) ==
-        getLineThis(classDeclaration.rightBracket.offset);
+  bool isClassWithEmptyBody(CompilationUnitMember declaration) {
+    return getLineThis(_getLeftBracket(declaration).offset) ==
+        getLineThis(_getRightBracket(declaration).offset);
   }
 
   /**
-   * @return <code>true</code> if selection range contains only whitespace or comments
+   * Return <code>true</code> if [range] contains only whitespace or comments.
    */
   bool isJustWhitespaceOrComment(SourceRange range) {
     String trimmedText = getRangeText(range).trim();
@@ -1070,12 +1067,15 @@
   }
 
   ClassMemberLocation prepareNewClassMemberLocation(
-      ClassOrMixinDeclaration classDeclaration,
+      CompilationUnitMember declaration,
       bool shouldSkip(ClassMember existingMember)) {
     String indent = getIndent(1);
     // Find the last target member.
     ClassMember targetMember = null;
-    List<ClassMember> members = classDeclaration.members;
+    List<ClassMember> members = _getMembers(declaration);
+    if (members == null) {
+      return null;
+    }
     for (ClassMember member in members) {
       if (shouldSkip(member)) {
         targetMember = member;
@@ -1089,11 +1089,11 @@
           endOfLine + endOfLine + indent, targetMember.end, '');
     }
     // At the beginning of the class.
-    String suffix = members.isNotEmpty || isClassWithEmptyBody(classDeclaration)
+    String suffix = members.isNotEmpty || isClassWithEmptyBody(declaration)
         ? endOfLine
         : '';
     return new ClassMemberLocation(
-        endOfLine + indent, classDeclaration.leftBracket.end, suffix);
+        endOfLine + indent, _getLeftBracket(declaration).end, suffix);
   }
 
   ClassMemberLocation prepareNewConstructorLocation(
@@ -1105,15 +1105,15 @@
   }
 
   ClassMemberLocation prepareNewFieldLocation(
-      ClassOrMixinDeclaration classDeclaration) {
+      CompilationUnitMember declaration) {
     return prepareNewClassMemberLocation(
-        classDeclaration, (member) => member is FieldDeclaration);
+        declaration, (member) => member is FieldDeclaration);
   }
 
   ClassMemberLocation prepareNewGetterLocation(
-      ClassOrMixinDeclaration classDeclaration) {
+      CompilationUnitMember declaration) {
     return prepareNewClassMemberLocation(
-        classDeclaration,
+        declaration,
         (member) =>
             member is FieldDeclaration ||
             member is ConstructorDeclaration ||
@@ -1121,9 +1121,9 @@
   }
 
   ClassMemberLocation prepareNewMethodLocation(
-      ClassOrMixinDeclaration classDeclaration) {
+      CompilationUnitMember declaration) {
     return prepareNewClassMemberLocation(
-        classDeclaration,
+        declaration,
         (member) =>
             member is FieldDeclaration ||
             member is ConstructorDeclaration ||
@@ -1236,6 +1236,33 @@
     return null;
   }
 
+  Token _getLeftBracket(CompilationUnitMember declaration) {
+    if (declaration is ClassOrMixinDeclaration) {
+      return declaration.leftBracket;
+    } else if (declaration is ExtensionDeclaration) {
+      return declaration.leftBracket;
+    }
+    return null;
+  }
+
+  List<ClassMember> _getMembers(CompilationUnitMember declaration) {
+    if (declaration is ClassOrMixinDeclaration) {
+      return declaration.members;
+    } else if (declaration is ExtensionDeclaration) {
+      return declaration.members;
+    }
+    return null;
+  }
+
+  Token _getRightBracket(CompilationUnitMember declaration) {
+    if (declaration is ClassOrMixinDeclaration) {
+      return declaration.rightBracket;
+    } else if (declaration is ExtensionDeclaration) {
+      return declaration.rightBracket;
+    }
+    return null;
+  }
+
   /**
    * @return the [InvertedCondition] for the given logical expression.
    */
@@ -1358,6 +1385,17 @@
  * Utilities to work with [Token]s.
  */
 class TokenUtils {
+  static List<Token> getNodeTokens(AstNode node) {
+    var result = <Token>[];
+    for (var token = node.beginToken;; token = token.next) {
+      result.add(token);
+      if (token == node.endToken) {
+        break;
+      }
+    }
+    return result;
+  }
+
   /**
    * @return [Token]s of the given Dart source, not <code>null</code>, may be empty if no
    *         tokens or some exception happens.
diff --git a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
index 0758a37..e9346c0 100644
--- a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
+++ b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
@@ -5,7 +5,6 @@
 import 'dart:convert';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -353,8 +352,7 @@
 
       // Don't use visitLibraryDirective as this won't generate a package
       // VName for libraries that don't have a library directive.
-      var libraryElement =
-          resolutionMap.elementDeclaredByCompilationUnit(node).library;
+      var libraryElement = node.declaredElement.library;
       if (libraryElement.definingCompilationUnit == node.declaredElement) {
         LibraryDirective libraryDirective;
         for (var directive in node.directives) {
@@ -433,8 +431,7 @@
   @override
   visitDeclaredIdentifier(DeclaredIdentifier node) {
     _handleVariableDeclaration(node.declaredElement, node.identifier,
-        subKind: schema.LOCAL_SUBKIND,
-        type: resolutionMap.elementDeclaredByDeclaredIdentifier(node).type);
+        subKind: schema.LOCAL_SUBKIND, type: node.declaredElement.type);
 
     // no children
   }
@@ -638,8 +635,7 @@
     // constructorName
     //
     var constructorName = node.constructorName;
-    var constructorElement =
-        resolutionMap.staticElementForConstructorReference(constructorName);
+    var constructorElement = constructorName.staticElement;
     if (constructorElement != null) {
       // anchor- ref/call
       _handleRefCallEdge(constructorElement,
@@ -786,11 +782,8 @@
     }
 
     // type
-    addEdge(
-        paramVName,
-        schema.TYPED_EDGE,
-        _vNameFromType(
-            resolutionMap.elementDeclaredByFormalParameter(node).type));
+    addEdge(paramVName, schema.TYPED_EDGE,
+        _vNameFromType(node.declaredElement.type));
 
     // visit children
     _safelyVisit(node.documentationComment);
@@ -851,7 +844,7 @@
     // variable
     _handleVariableDeclaration(node.declaredElement, node.name,
         subKind: isLocal ? schema.LOCAL_SUBKIND : schema.FIELD_SUBKIND,
-        type: resolutionMap.elementDeclaredByVariableDeclaration(node).type);
+        type: node.declaredElement.type);
 
     // visit children
     _safelyVisit(node.initializer);
@@ -1239,7 +1232,7 @@
     if (returnNode is TypeName) {
       // MethodDeclaration and FunctionDeclaration both return a TypeName from
       // returnType
-      if (resolutionMap.typeForTypeName(returnNode).isVoid) {
+      if (returnNode.type.isVoid) {
         returnTypeVName = voidBuiltin;
       } else {
         returnTypeVName =
@@ -1247,7 +1240,7 @@
       }
     } else if (returnNode is Identifier) {
       // ConstructorDeclaration returns an Identifier from returnType
-      if (resolutionMap.staticTypeForExpression(returnNode).isVoid) {
+      if (returnNode.staticType.isVoid) {
         returnTypeVName = voidBuiltin;
       } else {
         returnTypeVName =
@@ -1264,16 +1257,9 @@
     if (paramNodes != null) {
       for (FormalParameter paramNode in paramNodes.parameters) {
         var paramTypeVName = dynamicBuiltin;
-        if (!resolutionMap
-            .elementDeclaredByFormalParameter(paramNode)
-            .type
-            .isDynamic) {
+        if (!paramNode.declaredElement.type.isDynamic) {
           paramTypeVName = _vNameFromElement(
-              resolutionMap
-                  .elementDeclaredByFormalParameter(paramNode)
-                  .type
-                  .element,
-              schema.TAPP_KIND);
+              paramNode.declaredElement.type.element, schema.TAPP_KIND);
         }
         addEdge(funcTypeVName, schema.PARAM_EDGE, paramTypeVName,
             ordinalIntValue: i++);
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
new file mode 100644
index 0000000..c52000b
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -0,0 +1,61 @@
+// 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.
+
+/// An enumeration of lint names.
+class LintNames {
+  static const String always_require_non_null_named_parameters =
+      'always_require_non_null_named_parameters';
+  static const String always_specify_types = 'always_specify_types';
+  static const String annotate_overrides = 'annotate_overrides';
+  static const String avoid_annotating_with_dynamic =
+      'avoid_annotating_with_dynamic';
+  static const String avoid_empty_else = 'avoid_empty_else';
+  static const String avoid_init_to_null = 'avoid_init_to_null';
+  static const String avoid_return_types_on_setters =
+      'avoid_return_types_on_setters';
+  static const String avoid_types_on_closure_parameters =
+      'avoid_types_on_closure_parameters';
+  static const String await_only_futures = 'await_only_futures';
+  static const String curly_braces_in_flow_control_structures =
+      'curly_braces_in_flow_control_structures';
+  static const String empty_catches = 'empty_catches';
+  static const String empty_constructor_bodies = 'empty_constructor_bodies';
+  static const String empty_statements = 'empty_statements';
+  static const String no_duplicate_case_values = 'no_duplicate_case_values';
+  static const String non_constant_identifier_names =
+      'non_constant_identifier_names';
+  static const String null_closures = 'null_closures';
+  static const String prefer_collection_literals = 'prefer_collection_literals';
+  static const String prefer_conditional_assignment =
+      'prefer_conditional_assignment';
+  static const String prefer_const_constructors = 'prefer_const_constructors';
+  static const String prefer_const_declarations = 'prefer_const_declarations';
+  static const String prefer_equal_for_default_values =
+      'prefer_equal_for_default_values';
+  static const String prefer_expression_function_bodies =
+      'prefer_expression_function_bodies';
+  static const String prefer_final_fields = 'prefer_final_fields';
+  static const String prefer_final_locals = 'prefer_final_locals';
+  static const String prefer_for_elements_to_map_fromIterable =
+      'prefer_for_elements_to_map_fromIterable';
+  static const String prefer_int_literals = 'prefer_int_literals';
+  static const String prefer_if_elements_to_conditional_expressions =
+      'prefer_if_elements_to_conditional_expressions';
+  static const String prefer_is_empty = 'prefer_is_empty';
+  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 slash_for_doc_comments = 'slash_for_doc_comments';
+  static const String type_annotate_public_apis = 'type_annotate_public_apis';
+  static const String type_init_formals = 'type_init_formals';
+  static const String unawaited_futures = 'unawaited_futures';
+  static const String unnecessary_brace_in_string_interps =
+      'unnecessary_brace_in_string_interps';
+  static const String unnecessary_const = 'unnecessary_const';
+  static const String unnecessary_lambdas = 'unnecessary_lambdas';
+  static const String unnecessary_new = 'unnecessary_new';
+  static const String unnecessary_overrides = 'unnecessary_overrides';
+  static const String unnecessary_this = 'unnecessary_this';
+  static const String use_rethrow_when_possible = 'use_rethrow_when_possible';
+}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 1886f88..6c0b9d4 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -7,10 +7,10 @@
 
 import 'package:analysis_server/src/protocol_server.dart' hide Element;
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
-import 'package:analysis_server/src/services/correction/selection_analyzer.dart';
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
@@ -46,9 +46,8 @@
   final List<int> offsets = <int>[];
   final List<int> lengths = <int>[];
 
-  Expression rootExpression;
+  FunctionBody coveringFunctionBody;
   Expression singleExpression;
-  bool wholeStatementExpression = false;
   String stringLiteralPart;
   final List<SourceRange> occurrences = <SourceRange>[];
   final Map<Element, int> elementIds = <Element, int>{};
@@ -70,8 +69,10 @@
   CompilationUnitElement get unitElement => unit.declaredElement;
 
   String get _declarationKeyword {
-    if (_isPartOfConstantExpression(rootExpression)) {
+    if (_isPartOfConstantExpression(singleExpression)) {
       return "const";
+    } else if (_isLintEnabled(LintNames.prefer_final_locals)) {
+      return "final";
     } else {
       return "var";
     }
@@ -127,7 +128,8 @@
     occurrences.sort((a, b) => a.offset - b.offset);
     // If the whole expression of a statement is selected, like '1 + 2',
     // then convert it into a variable declaration statement.
-    if (wholeStatementExpression && occurrences.length == 1) {
+    if (singleExpression?.parent is ExpressionStatement &&
+        occurrences.length == 1) {
       String keyword = _declarationKeyword;
       String declarationSource = '$keyword $name = ';
       SourceEdit edit =
@@ -234,20 +236,42 @@
           'The selection end offset must be less then the length of the file.');
     }
 
-    String selectionStr;
+    var selectionStr = utils.getRangeText(selectionRange);
+
     // exclude whitespaces
     {
-      selectionStr = utils.getRangeText(selectionRange);
       int numLeading = countLeadingWhitespaces(selectionStr);
       int numTrailing = countTrailingWhitespaces(selectionStr);
       int offset = selectionRange.offset + numLeading;
       int end = selectionRange.end - numTrailing;
       selectionRange = new SourceRange(offset, end - offset);
     }
+
     // get covering node
     AstNode coveringNode =
         new NodeLocator(selectionRange.offset, selectionRange.end)
             .searchWithin(unit);
+
+    // We need an enclosing function.
+    // If it has a block body, we can add a new variable declaration statement
+    // into this block.  If it has an expression body, we can convert it into
+    // the block body first.
+    coveringFunctionBody = coveringNode?.thisOrAncestorOfType<FunctionBody>();
+    if (coveringFunctionBody == null) {
+      return new RefactoringStatus.fatal(
+          'An expression inside a function must be selected '
+          'to activate this refactoring.');
+    }
+
+    // part of string literal
+    if (coveringNode is StringLiteral) {
+      if (selectionRange.length != 0 &&
+          selectionRange.offset > coveringNode.offset &&
+          selectionRange.end < coveringNode.end) {
+        stringLiteralPart = selectionStr;
+        return new RefactoringStatus();
+      }
+    }
     // compute covering expressions
     for (AstNode node = coveringNode; node != null; node = node.parent) {
       AstNode parent = node.parent;
@@ -259,7 +283,7 @@
         continue;
       }
       if (node is ConstructorName || node is Label || node is TypeName) {
-        rootExpression = null;
+        singleExpression = null;
         coveringExpressionOffsets.clear();
         coveringExpressionLengths.clear();
         continue;
@@ -280,7 +304,7 @@
         if (element is ExecutableElement &&
             element.returnType != null &&
             element.returnType.isVoid) {
-          if (rootExpression == null) {
+          if (singleExpression == null) {
             return new RefactoringStatus.fatal(
                 'Cannot extract the void expression.',
                 newLocation_fromNode(node));
@@ -308,37 +332,16 @@
         }
       }
       // set selected expression
-      if (coveringExpressionOffsets.isEmpty) {
-        rootExpression = node;
+      if (singleExpression == null) {
+        singleExpression = node;
       }
       // add the expression range
       coveringExpressionOffsets.add(node.offset);
       coveringExpressionLengths.add(node.length);
     }
-    // We need an enclosing function.
-    // If it has a block body, we can add a new variable declaration statement
-    // into this block.  If it has an expression body, we can convert it into
-    // the block body first.
-    if (coveringNode == null ||
-        coveringNode.thisOrAncestorOfType<FunctionBody>() == null) {
-      return new RefactoringStatus.fatal(
-          'An expression inside a function must be selected '
-          'to activate this refactoring.');
-    }
-    // part of string literal
-    if (coveringNode is StringLiteral) {
-      if (selectionRange.length != 0 &&
-          selectionRange.offset > coveringNode.offset &&
-          selectionRange.end < coveringNode.end) {
-        stringLiteralPart = selectionStr;
-        return new RefactoringStatus();
-      }
-    }
     // single node selected
-    if (rootExpression != null) {
-      singleExpression = rootExpression;
+    if (singleExpression != null) {
       selectionRange = range.node(singleExpression);
-      wholeStatementExpression = singleExpression.parent is ExpressionStatement;
       return new RefactoringStatus();
     }
     // invalid selection
@@ -452,13 +455,9 @@
     return null;
   }
 
-  /**
-   * Checks if it is OK to extract the node with the given [SourceRange].
-   */
-  bool _isExtractable(SourceRange range) {
-    _ExtractExpressionAnalyzer analyzer = new _ExtractExpressionAnalyzer(range);
-    utils.unit.accept(analyzer);
-    return analyzer.status.isOK;
+  bool _isLintEnabled(String name) {
+    var analysisOptions = unitElement.context.analysisOptions;
+    return analysisOptions.isLintEnabled(name);
   }
 
   bool _isPartOfConstantExpression(AstNode node) {
@@ -500,24 +499,15 @@
   void _prepareOccurrences() {
     occurrences.clear();
     elementIds.clear();
+
     // prepare selection
     String selectionSource;
-    {
-      String rawSelectionSource = utils.getRangeText(selectionRange);
-      List<Token> selectionTokens =
-          TokenUtils.getTokens(rawSelectionSource, unit.featureSet);
-      selectionSource =
-          _encodeExpressionTokens(rootExpression, selectionTokens);
-    }
-    // prepare enclosing function
-    AstNode enclosingFunction;
-    {
-      AstNode selectionNode =
-          new NodeLocator(selectionOffset).searchWithin(unit);
-      enclosingFunction = getEnclosingExecutableNode(selectionNode);
+    if (singleExpression != null) {
+      var tokens = TokenUtils.getNodeTokens(singleExpression);
+      selectionSource = _encodeExpressionTokens(singleExpression, tokens);
     }
     // visit function
-    enclosingFunction.accept(new _OccurrencesVisitor(
+    coveringFunctionBody.accept(new _OccurrencesVisitor(
         this, occurrences, selectionSource, unit.featureSet));
   }
 
@@ -531,79 +521,6 @@
   }
 }
 
-/**
- * [SelectionAnalyzer] for [ExtractLocalRefactoringImpl].
- */
-class _ExtractExpressionAnalyzer extends SelectionAnalyzer {
-  final RefactoringStatus status = new RefactoringStatus();
-
-  _ExtractExpressionAnalyzer(SourceRange selection) : super(selection);
-
-  /**
-   * Records fatal error with given message.
-   */
-  void invalidSelection(String message) {
-    _invalidSelection(message, null);
-  }
-
-  @override
-  Object visitAssignmentExpression(AssignmentExpression node) {
-    super.visitAssignmentExpression(node);
-    Expression lhs = node.leftHandSide;
-    if (_isFirstSelectedNode(lhs)) {
-      _invalidSelection('Cannot extract the left-hand side of an assignment.',
-          newLocation_fromNode(lhs));
-    }
-    return null;
-  }
-
-  @override
-  Object visitSimpleIdentifier(SimpleIdentifier node) {
-    super.visitSimpleIdentifier(node);
-    if (_isFirstSelectedNode(node)) {
-      // name of declaration
-      if (node.inDeclarationContext()) {
-        invalidSelection('Cannot extract the name part of a declaration.');
-      }
-      // method name
-      Element element = node.staticElement;
-      if (element is FunctionElement || element is MethodElement) {
-        invalidSelection('Cannot extract a single method name.');
-      }
-      // name in property access
-      AstNode parent = node.parent;
-      if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
-        invalidSelection('Cannot extract name part of a property access.');
-      }
-      if (parent is PropertyAccess && identical(parent.propertyName, node)) {
-        invalidSelection('Cannot extract name part of a property access.');
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Records fatal error with given [message] and [location].
-   */
-  void _invalidSelection(String message, Location location) {
-    status.addFatalError(message, location);
-    reset();
-  }
-
-  bool _isFirstSelectedNode(AstNode node) => node == firstSelectedNode;
-}
-
-class _HasStatementVisitor extends GeneralizingAstVisitor {
-  bool result = false;
-
-  _HasStatementVisitor();
-
-  @override
-  visitStatement(Statement node) {
-    result = true;
-  }
-}
-
 class _OccurrencesVisitor extends GeneralizingAstVisitor<void> {
   final ExtractLocalRefactoringImpl ref;
   final List<SourceRange> occurrences;
@@ -614,20 +531,19 @@
       this.ref, this.occurrences, this.selectionSource, this.featureSet);
 
   @override
-  void visitBinaryExpression(BinaryExpression node) {
-    if (!_hasStatements(node)) {
-      _tryToFindOccurrenceFragments(node);
-      return;
-    }
-    super.visitBinaryExpression(node);
+  void visitExpression(Expression node) {
+    _tryToFindOccurrence(node);
+    super.visitExpression(node);
   }
 
   @override
-  void visitExpression(Expression node) {
-    if (ref._isExtractable(range.node(node))) {
-      _tryToFindOccurrence(node);
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    var parent = node.parent;
+    if (parent is VariableDeclaration && parent.name == node ||
+        parent is AssignmentExpression && parent.leftHandSide == node) {
+      return;
     }
-    super.visitExpression(node);
+    super.visitSimpleIdentifier(node);
   }
 
   @override
@@ -659,48 +575,13 @@
     }
   }
 
-  bool _hasStatements(AstNode root) {
-    _HasStatementVisitor visitor = new _HasStatementVisitor();
-    root.accept(visitor);
-    return visitor.result;
-  }
-
   void _tryToFindOccurrence(Expression node) {
-    String nodeSource = ref.utils.getNodeText(node);
-    List<Token> nodeTokens = TokenUtils.getTokens(nodeSource, featureSet);
-    nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
+    var nodeTokens = TokenUtils.getNodeTokens(node);
+    var nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
     if (nodeSource == selectionSource) {
       _addOccurrence(range.node(node));
     }
   }
-
-  void _tryToFindOccurrenceFragments(Expression node) {
-    int nodeOffset = node.offset;
-    String nodeSource = ref.utils.getNodeText(node);
-    List<Token> nodeTokens = TokenUtils.getTokens(nodeSource, featureSet);
-    nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
-    // find "selection" in "node" tokens
-    int lastIndex = 0;
-    while (true) {
-      // find next occurrence
-      int index = nodeSource.indexOf(selectionSource, lastIndex);
-      if (index == -1) {
-        break;
-      }
-      lastIndex = index + selectionSource.length;
-      // find start/end tokens
-      int startTokenIndex =
-          countMatches(nodeSource.substring(0, index), _TOKEN_SEPARATOR);
-      int endTokenIndex =
-          countMatches(nodeSource.substring(0, lastIndex), _TOKEN_SEPARATOR);
-      Token startToken = nodeTokens[startTokenIndex];
-      Token endToken = nodeTokens[endTokenIndex - 1];
-      // add occurrence range
-      int start = nodeOffset + startToken.offset;
-      int end = nodeOffset + endToken.end;
-      _addOccurrence(range.startOffsetEndOffset(start, end));
-    }
-  }
 }
 
 class _TokenLocalElementVisitor extends RecursiveAstVisitor {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 233123c..a495f56 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -20,7 +20,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -452,8 +451,7 @@
     AstNode parent = _parentMember.parent;
     // top-level function
     if (parent is CompilationUnit) {
-      LibraryElement libraryElement =
-          resolutionMap.elementDeclaredByCompilationUnit(parent).library;
+      LibraryElement libraryElement = parent.declaredElement.library;
       return validateCreateFunction(searchEngine, libraryElement, name);
     }
     // method of class
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 63a2193..a43fac9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -15,6 +15,7 @@
 import 'package:analysis_server/src/services/refactoring/move_file.dart';
 import 'package:analysis_server/src/services/refactoring/rename_class_member.dart';
 import 'package:analysis_server/src/services/refactoring/rename_constructor.dart';
+import 'package:analysis_server/src/services/refactoring/rename_extension_member.dart';
 import 'package:analysis_server/src/services/refactoring/rename_import.dart';
 import 'package:analysis_server/src/services/refactoring/rename_label.dart';
 import 'package:analysis_server/src/services/refactoring/rename_library.dart';
@@ -484,6 +485,9 @@
     if (element.enclosingElement is ClassElement) {
       return new RenameClassMemberRefactoringImpl(workspace, session, element);
     }
+    if (element.enclosingElement is ExtensionElement) {
+      return RenameExtensionMemberRefactoringImpl(workspace, session, element);
+    }
     return null;
   }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
new file mode 100644
index 0000000..f8b7eb2
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
@@ -0,0 +1,227 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+    hide Element, ElementKind;
+import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analysis_server/src/services/refactoring/rename.dart';
+import 'package:analysis_server/src/services/refactoring/visible_ranges_computer.dart';
+import 'package:analysis_server/src/services/search/hierarchy.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/session_helper.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A [Refactoring] for renaming extension member [Element]s.
+ */
+class RenameExtensionMemberRefactoringImpl extends RenameRefactoringImpl {
+  final AnalysisSessionHelper sessionHelper;
+
+  _ExtensionMemberValidator _validator;
+
+  RenameExtensionMemberRefactoringImpl(
+      RefactoringWorkspace workspace, AnalysisSession session, Element element)
+      : sessionHelper = AnalysisSessionHelper(session),
+        super(workspace, element);
+
+  @override
+  String get refactoringName {
+    if (element is TypeParameterElement) {
+      return "Rename Type Parameter";
+    }
+    if (element is FieldElement) {
+      return "Rename Field";
+    }
+    return "Rename Method";
+  }
+
+  @override
+  Future<RefactoringStatus> checkFinalConditions() {
+    _validator = _ExtensionMemberValidator.forRename(
+        searchEngine, sessionHelper, element, newName);
+    return _validator.validate();
+  }
+
+  @override
+  Future<RefactoringStatus> checkInitialConditions() async {
+    RefactoringStatus result = await super.checkInitialConditions();
+    if (element is MethodElement && (element as MethodElement).isOperator) {
+      result.addFatalError('Cannot rename operator.');
+    }
+    return Future<RefactoringStatus>.value(result);
+  }
+
+  @override
+  RefactoringStatus checkNewName() {
+    RefactoringStatus result = super.checkNewName();
+    if (element is FieldElement) {
+      result.addStatus(validateFieldName(newName));
+    }
+    if (element is MethodElement) {
+      result.addStatus(validateMethodName(newName));
+    }
+    return result;
+  }
+
+  @override
+  Future<void> fillChange() async {
+    var processor = RenameProcessor(workspace, change, newName);
+
+    // Update the declaration.
+    var renameElement = element;
+    if (renameElement.isSynthetic && renameElement is FieldElement) {
+      processor.addDeclarationEdit(renameElement.getter);
+      processor.addDeclarationEdit(renameElement.setter);
+    } else {
+      processor.addDeclarationEdit(renameElement);
+    }
+
+    // Update references.
+    processor.addReferenceEdits(_validator.references);
+  }
+}
+
+/**
+ * Helper to check if the created or renamed [Element] will cause any conflicts.
+ */
+class _ExtensionMemberValidator {
+  final SearchEngine searchEngine;
+  final AnalysisSessionHelper sessionHelper;
+  final LibraryElement library;
+  final Element element;
+  final ExtensionElement elementExtension;
+  final ElementKind elementKind;
+  final String name;
+  final bool isRename;
+
+  final RefactoringStatus result = RefactoringStatus();
+  final List<SearchMatch> references = <SearchMatch>[];
+
+  _ExtensionMemberValidator.forRename(
+      this.searchEngine, this.sessionHelper, Element element, this.name)
+      : isRename = true,
+        library = element.library,
+        element = element,
+        elementExtension = element.enclosingElement,
+        elementKind = element.kind;
+
+  Future<RefactoringStatus> validate() async {
+    // Check if there is a member with "newName" in the extension.
+    for (Element newNameMember in getChildren(elementExtension, name)) {
+      result.addError(
+        format(
+          "Extension '{0}' already declares {1} with name '{2}'.",
+          elementExtension.displayName,
+          getElementKindName(newNameMember),
+          name,
+        ),
+        newLocation_fromElement(newNameMember),
+      );
+    }
+
+    await _prepareReferences();
+
+    // usage of the renamed Element is shadowed by a local element
+    {
+      _MatchShadowedByLocal conflict = await _getShadowingLocalElement();
+      if (conflict != null) {
+        LocalElement localElement = conflict.localElement;
+        result.addError(
+          format(
+            "Usage of renamed {0} will be shadowed by {1} '{2}'.",
+            elementKind.displayName,
+            getElementKindName(localElement),
+            localElement.displayName,
+          ),
+          newLocation_fromMatch(conflict.match),
+        );
+      }
+    }
+
+    return result;
+  }
+
+  Future<_MatchShadowedByLocal> _getShadowingLocalElement() async {
+    var localElementMap = <CompilationUnitElement, List<LocalElement>>{};
+    var visibleRangeMap = <LocalElement, SourceRange>{};
+
+    Future<List<LocalElement>> getLocalElements(Element element) async {
+      var unitElement = element.getAncestor((e) => e is CompilationUnitElement);
+      var localElements = localElementMap[unitElement];
+
+      if (localElements == null) {
+        var result = await sessionHelper.getResolvedUnitByElement(element);
+        var unit = result.unit;
+
+        var collector = _LocalElementsCollector(name);
+        unit.accept(collector);
+        localElements = collector.elements;
+        localElementMap[unitElement] = localElements;
+
+        visibleRangeMap.addAll(VisibleRangesComputer.forNode(unit));
+      }
+
+      return localElements;
+    }
+
+    for (SearchMatch match in references) {
+      // Qualified reference cannot be shadowed by local elements.
+      if (match.isQualified) {
+        continue;
+      }
+      // Check local elements that might shadow the reference.
+      var localElements = await getLocalElements(match.element);
+      for (LocalElement localElement in localElements) {
+        SourceRange elementRange = visibleRangeMap[localElement];
+        if (elementRange != null &&
+            elementRange.intersects(match.sourceRange)) {
+          return _MatchShadowedByLocal(match, localElement);
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Fills [references] with references to the [element].
+   */
+  Future<void> _prepareReferences() async {
+    if (!isRename) return;
+
+    references.addAll(
+      await searchEngine.searchReferences(element),
+    );
+  }
+}
+
+class _LocalElementsCollector extends GeneralizingAstVisitor<void> {
+  final String name;
+  final List<LocalElement> elements = [];
+
+  _LocalElementsCollector(this.name);
+
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is LocalElement && element.name == name) {
+      elements.add(element);
+    }
+  }
+}
+
+class _MatchShadowedByLocal {
+  final SearchMatch match;
+  final LocalElement localElement;
+
+  _MatchShadowedByLocal(this.match, this.localElement);
+}
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index bbac8d1..9d157a5 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -64,6 +64,28 @@
   return matches.map((match) => match.element).cast<ClassElement>().toSet();
 }
 
+/// Return the non-synthetic children of the given [extension]. This includes
+/// fields, accessors and methods, but excludes synthetic elements.
+List<Element> getExtensionMembers(ExtensionElement extension, [String name]) {
+  List<Element> members = <Element>[];
+  visitChildren(extension, (Element element) {
+    if (element.isSynthetic) {
+      return false;
+    }
+    if (name != null && element.displayName != name) {
+      return false;
+    }
+    if (element is ExecutableElement) {
+      members.add(element);
+    }
+    if (element is FieldElement) {
+      members.add(element);
+    }
+    return false;
+  });
+  return members;
+}
+
 /**
  * @return all implementations of the given {@link ClassMemberElement} is its superclasses and
  *         their subclasses.
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index 57d8ac6..112ee48 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -895,7 +895,7 @@
     );
     ul([
       'what you were doing',
-      'what occured',
+      'what occurred',
       'what you think the expected behavior should have been',
     ], (line) => buf.writeln(line));
 
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index 3eb7abb..eccd264 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -334,6 +334,9 @@
 
         if (parent is ArgumentList ||
             parent is ExpressionFunctionBody && parent.expression == node ||
+            parent is ForElement && parent.body == node ||
+            parent is IfElement && parent.thenElement == node ||
+            parent is IfElement && parent.elseElement == node ||
             parent is ListLiteral ||
             parent is NamedExpression && parent.expression == node ||
             parent is Statement) {
diff --git a/pkg/analysis_server/lib/src/utilities/request_statistics.dart b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
index bffd70f..b9e3b4b 100644
--- a/pkg/analysis_server/lib/src/utilities/request_statistics.dart
+++ b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
@@ -5,6 +5,8 @@
 import 'dart:convert';
 
 import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/channel/byte_stream_channel.dart';
 
 /// Helper for tracking request handling statistics.
 ///
@@ -12,9 +14,31 @@
 class RequestStatisticsHelper {
   final Map<String, _RequestStatistics> _statisticsMap = {};
 
-  /// The sink to write statistics to.
-  /// It is set externally when we get to `AnalysisServer` instance.
-  StringSink sink;
+  /// The [StringSink] to which performance logger should copy its output.
+  _ServerLogStringSink _perfLoggerStringSink;
+
+  /// The channel to send 'server.log' notifications to.
+  ByteStreamServerChannel _serverChannel;
+
+  /// Is `true` if the client subscribed for "server.log" notification.
+  bool _isNotificationSubscribed = false;
+
+  RequestStatisticsHelper() {
+    _perfLoggerStringSink = _ServerLogStringSink(this);
+  }
+
+  /// Set whether the client subscribed for "server.log" notification.
+  set isNotificationSubscribed(bool value) {
+    _isNotificationSubscribed = value;
+  }
+
+  /// The [StringSink] to which performance logger should copy its output.
+  StringSink get perfLoggerStringSink => _perfLoggerStringSink;
+
+  /// The channel sets itself using this method.
+  set serverChannel(ByteStreamServerChannel serverChannel) {
+    _serverChannel = serverChannel;
+  }
 
   /// Add a time marker item to the data associated with the [request].
   void addItemTimeNow(Request request, String name) {
@@ -58,25 +82,20 @@
   /// The server finished processing a request, and sends the [response].
   /// Record the time when the response is about to be sent to the client.
   void addResponse(Response response) {
+    if (!_isNotificationSubscribed) return;
+    if (_serverChannel == null) return;
+
     var id = response.id;
     var stat = _statisticsMap.remove(id);
     if (stat != null) {
       stat.responseTime = DateTime.now();
-
-      if (sink != null) {
-        sink.writeln(
-          json.encode(
-            {
-              'requestStatistics': stat.toJson(),
-            },
-          ),
-        );
-      }
+      _sendLogEntry(ServerLogEntryKind.RESPONSE, stat.toJson());
     }
   }
 
   void logNotification(Notification notification) {
-    if (sink == null) return;
+    if (!_isNotificationSubscribed) return;
+    if (_serverChannel == null) return;
 
     var event = notification.event;
 
@@ -105,15 +124,12 @@
       }
     }
 
-    sink.writeln(
-      json.encode({
-        'notification': map,
-      }),
-    );
+    _sendLogEntry(ServerLogEntryKind.NOTIFICATION, map);
   }
 
   void _logRequest(Request request) {
-    if (sink == null) return;
+    if (!_isNotificationSubscribed) return;
+    if (_serverChannel == null) return;
 
     var method = request.method;
     var map = <String, Object>{
@@ -137,10 +153,22 @@
       map = request.toJson();
     }
 
-    sink.writeln(
-      json.encode({
-        'request': map,
-      }),
+    _sendLogEntry(ServerLogEntryKind.REQUEST, map);
+  }
+
+  void _sendLogEntry(ServerLogEntryKind kind, Object data) {
+    if (!_isNotificationSubscribed) return;
+    if (_serverChannel == null) return;
+
+    _serverChannel.sendNotification(
+      Notification(
+        'server.log',
+        <String, Object>{
+          'time': DateTime.now().millisecondsSinceEpoch,
+          'kind': kind.toJson(),
+          'data': data,
+        },
+      ),
     );
   }
 }
@@ -161,16 +189,15 @@
   );
 
   Map<String, Object> toJson() {
-    var baseTime = clientRequestTime.millisecondsSinceEpoch;
     var map = {
       'id': id,
       'method': method,
-      'clientRequestTime': baseTime,
-      'serverRequestTime': serverRequestTime.millisecondsSinceEpoch - baseTime,
-      'responseTime': responseTime.millisecondsSinceEpoch - baseTime,
+      'clientRequestTime': clientRequestTime.millisecondsSinceEpoch,
+      'serverRequestTime': serverRequestTime.millisecondsSinceEpoch,
+      'responseTime': responseTime.millisecondsSinceEpoch,
     };
     if (items.isNotEmpty) {
-      map['items'] = items.map((item) => item.toJson(baseTime)).toList();
+      map['items'] = items.map((item) => item.toJson()).toList();
     }
     return map;
   }
@@ -188,13 +215,35 @@
 
   _RequestStatisticsItem(this.name, {this.timeValue});
 
-  Map<String, Object> toJson(int baseTimeMillis) {
+  Map<String, Object> toJson() {
     if (timeValue != null) {
       return {
         'name': name,
-        'timeValue': timeValue.millisecondsSinceEpoch - baseTimeMillis,
+        'timeValue': timeValue.millisecondsSinceEpoch,
       };
     }
     throw StateError('Unknown value: $name');
   }
 }
+
+class _ServerLogStringSink implements StringSink {
+  final RequestStatisticsHelper helper;
+
+  _ServerLogStringSink(this.helper);
+
+  void write(Object obj) {
+    throw UnimplementedError();
+  }
+
+  void writeAll(Iterable objects, [String separator = '']) {
+    throw UnimplementedError();
+  }
+
+  void writeCharCode(int charCode) {
+    throw UnimplementedError();
+  }
+
+  void writeln([Object obj = '']) {
+    helper._sendLogEntry(ServerLogEntryKind.RAW, '$obj');
+  }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/tee_string_sink.dart b/pkg/analysis_server/lib/src/utilities/tee_string_sink.dart
new file mode 100644
index 0000000..0180b9d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/tee_string_sink.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.
+
+/**
+ * A [StringSink] that writes into two other [StringSink]s.
+ */
+class TeeStringSink implements StringSink {
+  final StringSink sink1;
+  final StringSink sink2;
+
+  TeeStringSink(this.sink1, this.sink2);
+
+  void write(Object obj) {
+    sink1.write(obj);
+    sink2.write(obj);
+  }
+
+  void writeAll(Iterable objects, [String separator = ""]) {
+    sink1.writeAll(objects, separator);
+    sink2.writeAll(objects, separator);
+  }
+
+  void writeCharCode(int charCode) {
+    sink1.writeCharCode(charCode);
+    sink2.writeCharCode(charCode);
+  }
+
+  void writeln([Object obj = ""]) {
+    sink1.writeln(obj);
+    sink2.writeln(obj);
+  }
+}
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 3850a81..20a9e0e 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -2,7 +2,7 @@
 publish_to: none
 
 environment:
-  sdk: '>=2.1.0-dev.5.0 <3.0.0'
+  sdk: '>=2.2.2 <3.0.0'
 
 dependencies:
   analyzer: any
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 5a29769..6ec7193 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -19,6 +19,7 @@
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:linter/src/rules.dart';
 
 import 'src/utilities/mock_packages.dart';
 
@@ -129,8 +130,10 @@
   }
 
   /// Create an analysis options file based on the given arguments.
-  void createAnalysisOptionsFile({List<String> experiments}) {
+  void createAnalysisOptionsFile(
+      {List<String> experiments, List<String> lints}) {
     StringBuffer buffer = new StringBuffer();
+
     if (experiments != null) {
       buffer.writeln('analyzer:');
       buffer.writeln('  enable-experiment:');
@@ -138,6 +141,15 @@
         buffer.writeln('    - $experiment');
       }
     }
+
+    if (lints != null) {
+      buffer.writeln('linter:');
+      buffer.writeln('  rules:');
+      for (String lint in lints) {
+        buffer.writeln('    - $lint');
+      }
+    }
+
     newFile(analysisOptionsPath, content: buffer.toString());
     if (_driver != null) {
       createAnalysisContexts();
@@ -166,6 +178,8 @@
   }
 
   void setUp() {
+    registerLintRules();
+
     setupResourceProvider();
     overlayResourceProvider = OverlayResourceProvider(resourceProvider);
 
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index dc47e1d..28a5b6e 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -892,38 +892,38 @@
 class C implements B {}
 class D with C {}
 ''', [
-      token('class', null, null),
-      token('A', 'Type',
-          ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
-      token('{', null, null),
-      token('}', null, null),
-      token('class', null, null),
-      token('B', 'Type',
-          ['declaration']), //token('B', 'dart:core;Type', ['declaration']),
-      token('extends', null, null),
-      token('A', 'dart:core;Type<A>', [
+      token('class', 0, null, null),
+      token('A', 6, 'Type',
+          ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+      token('{', 8, null, null),
+      token('}', 9, null, null),
+      token('class', 11, null, null),
+      token('B', 17, 'Type',
+          ['declaration']), //token('B', 17, 'dart:core;Type', ['declaration']),
+      token('extends', 19, null, null),
+      token('A', 27, 'dart:core;Type<A>', [
         'reference'
-      ]), //token('A', 'dart:core;Type<$testFileUri;A>', ['reference']),
-      token('{', null, null),
-      token('}', null, null),
-      token('class', null, null),
-      token('C', 'Type',
-          ['declaration']), //token('C', 'dart:core;Type', ['declaration']),
-      token('implements', null, null),
-      token('B', 'dart:core;Type<B>', [
+      ]), //token('A', 27, 'dart:core;Type<$testFileUri;A>', ['reference']),
+      token('{', 29, null, null),
+      token('}', 30, null, null),
+      token('class', 32, null, null),
+      token('C', 38, 'Type',
+          ['declaration']), //token('C', 38, 'dart:core;Type', ['declaration']),
+      token('implements', 40, null, null),
+      token('B', 51, 'dart:core;Type<B>', [
         'reference'
-      ]), //token('B', 'dart:core;Type<$testFileUri;B>', ['reference']),
-      token('{', null, null),
-      token('}', null, null),
-      token('class', null, null),
-      token('D', 'Type',
-          ['declaration']), //token('D', 'dart:core;Type', ['declaration']),
-      token('with', null, null),
-      token('C', 'dart:core;Type<C>', [
+      ]), //token('B', 51, 'dart:core;Type<$testFileUri;B>', ['reference']),
+      token('{', 53, null, null),
+      token('}', 54, null, null),
+      token('class', 56, null, null),
+      token('D', 62, 'Type',
+          ['declaration']), //token('D', 62, 'dart:core;Type', ['declaration']),
+      token('with', 64, null, null),
+      token('C', 69, 'dart:core;Type<C>', [
         'reference'
-      ]), //token('C', 'dart:core;Type<$testFileUri;C>', ['reference']),
-      token('{', null, null),
-      token('}', null, null),
+      ]), //token('C', 69, 'dart:core;Type<$testFileUri;C>', ['reference']),
+      token('{', 71, null, null),
+      token('}', 72, null, null),
     ]);
   }
 
@@ -931,19 +931,19 @@
     await expectTokens('''
 List<int> x = null;
 ''', [
-      token('List', 'dart:core;Type<List>', [
+      token('List', 0, 'dart:core;Type<List>', [
         'reference'
-      ]), //token('List', 'dart:core;Type<dart:core;List>', ['reference']),
-      token('<', null, null),
-      token('int', 'dart:core;Type<int>', [
+      ]), //token('List', 0, 'dart:core;Type<dart:core;List>', ['reference']),
+      token('<', 4, null, null),
+      token('int', 5, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('>', null, null),
-      token('x', 'List',
-          ['declaration']), //token('x', 'dart:core;List', ['declaration']),
-      token('=', null, null),
-      token('null', null, null),
-      token(';', null, null),
+      ]), //token('int', 5, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('>', 8, null, null),
+      token('x', 10, 'List',
+          ['declaration']), //token('x', 10, 'dart:core;List', ['declaration']),
+      token('=', 12, null, null),
+      token('null', 14, null, null),
+      token(';', 18, null, null),
     ]);
   }
 
@@ -951,15 +951,16 @@
     await expectTokens('''
 var x = 'a'.length;
 ''', [
-      token('var', null, null),
-      token('x', 'int',
-          ['declaration']), //token('x', 'dart:core;int', ['declaration']),
-      token('=', null, null),
-      token("'a'", 'String', null), //token("'a'", 'dart:core;String', null),
-      token('.', null, null),
-      token('length', 'int',
-          ['reference']), //token('length', 'dart:core;int', ['reference']),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'int',
+          ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+      token('=', 6, null, null),
+      token("'a'", 8, 'String',
+          null), //token("'a'", 8, 'dart:core;String', null),
+      token('.', 11, null, null),
+      token('length', 12, 'int',
+          ['reference']), //token('length', 12, 'dart:core;int', ['reference']),
+      token(';', 18, null, null),
     ]);
   }
 
@@ -967,12 +968,13 @@
     await expectTokens('''
 var x = true;
 ''', [
-      token('var', null, null),
-      token('x', 'bool',
-          ['declaration']), //token('x', 'dart:core;bool', ['declaration']),
-      token('=', null, null),
-      token('true', 'bool', null), //token('true', 'dart:core;bool', null),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'bool',
+          ['declaration']), //token('x', 4, 'dart:core;bool', ['declaration']),
+      token('=', 6, null, null),
+      token(
+          'true', 8, 'bool', null), //token('true', 8, 'dart:core;bool', null),
+      token(';', 12, null, null),
     ]);
   }
 
@@ -980,12 +982,14 @@
     await expectTokens('''
 var x = 3.4;
 ''', [
-      token('var', null, null),
-      token('x', 'double',
-          ['declaration']), //token('x', 'dart:core;double', ['declaration']),
-      token('=', null, null),
-      token('3.4', 'double', null), //token('3.4', 'dart:core;double', null),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'double', [
+        'declaration'
+      ]), //token('x', 4, 'dart:core;double', ['declaration']),
+      token('=', 6, null, null),
+      token('3.4', 8, 'double',
+          null), //token('3.4', 8, 'dart:core;double', null),
+      token(';', 11, null, null),
     ]);
   }
 
@@ -993,12 +997,12 @@
     await expectTokens('''
 var x = 7;
 ''', [
-      token('var', null, null),
-      token('x', 'int',
-          ['declaration']), //token('x', 'dart:core;int', ['declaration']),
-      token('=', null, null),
-      token('7', 'int', null), //token('7', 'dart:core;int', null),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'int',
+          ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+      token('=', 6, null, null),
+      token('7', 8, 'int', null), //token('7', 8, 'dart:core;int', null),
+      token(';', 9, null, null),
     ]);
   }
 
@@ -1006,18 +1010,18 @@
     await expectTokens('''
 var x = <int>[];
 ''', [
-      token('var', null, null),
-      token('x', 'List',
-          ['declaration']), //token('x', 'dart:core;List', ['declaration']),
-      token('=', null, null),
-      token('<', null, null),
-      token("int", 'dart:core;Type<int>', [
+      token('var', 0, null, null),
+      token('x', 4, 'List',
+          ['declaration']), //token('x', 4, 'dart:core;List', ['declaration']),
+      token('=', 6, null, null),
+      token('<', 8, null, null),
+      token("int", 9, 'dart:core;Type<int>', [
         'reference'
-      ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
-      token('>', null, null),
-      token('[', null, null),
-      token(']', null, null),
-      token(';', null, null),
+      ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('>', 12, null, null),
+      token('[', 13, null, null),
+      token(']', 14, null, null),
+      token(';', 15, null, null),
     ]);
   }
 
@@ -1025,22 +1029,22 @@
     await expectTokens('''
 var x = <int, int>{};
 ''', [
-      token('var', null, null),
-      token('x', 'Map',
-          ['declaration']), //token('x', 'dart:core;Map', ['declaration']),
-      token('=', null, null),
-      token('<', null, null),
-      token("int", 'dart:core;Type<int>', [
+      token('var', 0, null, null),
+      token('x', 4, 'Map',
+          ['declaration']), //token('x', 4, 'dart:core;Map', ['declaration']),
+      token('=', 6, null, null),
+      token('<', 8, null, null),
+      token("int", 9, 'dart:core;Type<int>', [
         'reference'
-      ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
+      ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
 //      token(',', null, null),
-      token("int", 'dart:core;Type<int>', [
+      token("int", 14, 'dart:core;Type<int>', [
         'reference'
-      ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
-      token('>', null, null),
-      token('{', null, null),
-      token('}', null, null),
-      token(';', null, null),
+      ]), //token("int", 14, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('>', 17, null, null),
+      token('{', 18, null, null),
+      token('}', 19, null, null),
+      token(';', 20, null, null),
     ]);
   }
 
@@ -1048,11 +1052,11 @@
     await expectTokens('''
 var x = null;
 ''', [
-      token('var', null, null),
-      token('x', 'dynamic', ['declaration']),
-      token('=', null, null),
-      token('null', null, null),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'dynamic', ['declaration']),
+      token('=', 6, null, null),
+      token('null', 8, null, null),
+      token(';', 12, null, null),
     ]);
   }
 
@@ -1060,18 +1064,18 @@
     await expectTokens('''
 var x = <int>{};
 ''', [
-      token('var', null, null),
-      token('x', 'Set',
-          ['declaration']), //token('x', 'dart:core;Set', ['declaration']),
-      token('=', null, null),
-      token('<', null, null),
-      token("int", 'dart:core;Type<int>', [
+      token('var', 0, null, null),
+      token('x', 4, 'Set',
+          ['declaration']), //token('x', 4, 'dart:core;Set', ['declaration']),
+      token('=', 6, null, null),
+      token('<', 8, null, null),
+      token("int", 9, 'dart:core;Type<int>', [
         'reference'
-      ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
-      token('>', null, null),
-      token('{', null, null),
-      token('}', null, null),
-      token(';', null, null),
+      ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('>', 12, null, null),
+      token('{', 13, null, null),
+      token('}', 14, null, null),
+      token(';', 15, null, null),
     ]);
   }
 
@@ -1079,12 +1083,14 @@
     await expectTokens('''
 var x = 'a';
 ''', [
-      token('var', null, null),
-      token('x', 'String',
-          ['declaration']), //token('x', 'dart:core;String', ['declaration']),
-      token('=', null, null),
-      token("'a'", 'String', null), //token("'a'", 'dart:core;String', null),
-      token(';', null, null),
+      token('var', 0, null, null),
+      token('x', 4, 'String', [
+        'declaration'
+      ]), //token('x', 4, 'dart:core;String', ['declaration']),
+      token('=', 6, null, null),
+      token("'a'", 8, 'String',
+          null), //token("'a'", 8, 'dart:core;String', null),
+      token(';', 11, null, null),
     ]);
   }
 
@@ -1094,32 +1100,32 @@
   String c(int x, int y) {}
 }
 ''', [
-      token('class', null, null),
-      token('A', 'Type',
-          ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
-      token('{', null, null),
-      token('String', 'dart:core;Type<String>', [
+      token('class', 0, null, null),
+      token('A', 6, 'Type',
+          ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+      token('{', 8, null, null),
+      token('String', 12, 'dart:core;Type<String>', [
         'reference'
-      ]), //token('String', 'dart:core;Type<dart:core;String>', ['reference']),
-      token('c',
+      ]), //token('String', 12, 'dart:core;Type<dart:core;String>', ['reference']),
+      token('c', 19,
           'String Function(int, int)', //'dart:core;String Function(dart:core;int, dart:core;int)',
           ['declaration']),
-      token('(', null, null),
-      token('int', 'dart:core;Type<int>', [
+      token('(', 20, null, null),
+      token('int', 21, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('x', 'int',
-          ['declaration']), //token('x', 'dart:core;int', ['declaration']),
+      ]), //token('int', 21, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('x', 25, 'int',
+          ['declaration']), //token('x', 25, 'dart:core;int', ['declaration']),
 //      token(',', null, null),
-      token('int', 'dart:core;Type<int>', [
+      token('int', 28, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('y', 'int',
-          ['declaration']), //token('y', 'dart:core;int', ['declaration']),
-      token(')', null, null),
-      token('{', null, null),
-      token('}', null, null),
-      token('}', null, null),
+      ]), //token('int', 28, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('y', 32, 'int',
+          ['declaration']), //token('y', 32, 'dart:core;int', ['declaration']),
+      token(')', 33, null, null),
+      token('{', 35, null, null),
+      token('}', 36, null, null),
+      token('}', 38, null, null),
     ]);
   }
 
@@ -1127,22 +1133,23 @@
     await expectTokens('''
 var x = 'radar'.indexOf('r', 1);
 ''', [
-      token('var', null, null),
-      token('x', 'int',
-          ['declaration']), //token('x', 'dart:core;int', ['declaration']),
-      token('=', null, null),
-      token("'radar'", 'String',
-          null), //token("'radar'", 'dart:core;String', null),
-      token('.', null, null),
-      token('indexOf',
+      token('var', 0, null, null),
+      token('x', 4, 'int',
+          ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+      token('=', 6, null, null),
+      token("'radar'", 8, 'String',
+          null), //token("'radar'", 8, 'dart:core;String', null),
+      token('.', 15, null, null),
+      token('indexOf', 16,
           'int Function(Pattern, int)', //'dart:core;int Function(dart:core;Pattern, dart:core;int)',
           ['reference']),
-      token('(', null, null),
-      token("'r'", 'String', null), //token("'r'", 'dart:core;String', null),
+      token('(', 23, null, null),
+      token("'r'", 24, 'String',
+          null), //token("'r'", 24, 'dart:core;String', null),
 //      token(',', null, null),
-      token('1', 'int', null), //token('1', 'dart:core;int', null),
-      token(')', null, null),
-      token(';', null, null),
+      token('1', 29, 'int', null), //token('1', 29, 'dart:core;int', null),
+      token(')', 30, null, null),
+      token(';', 31, null, null),
     ]);
   }
 
@@ -1152,29 +1159,29 @@
 class B {}
 mixin D on A implements B {}
 ''', [
-      token('class', null, null),
-      token('A', 'Type',
-          ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
-      token('{', null, null),
-      token('}', null, null),
-      token('class', null, null),
-      token('B', 'Type',
-          ['declaration']), //token('B', 'dart:core;Type', ['declaration']),
-      token('{', null, null),
-      token('}', null, null),
-      token('mixin', null, null),
-      token('D', 'Type',
-          ['declaration']), //token('D', 'dart:core;Type', ['declaration']),
-      token('on', null, null),
-      token('A', 'dart:core;Type<A>', [
+      token('class', 0, null, null),
+      token('A', 6, 'Type',
+          ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+      token('{', 8, null, null),
+      token('}', 9, null, null),
+      token('class', 11, null, null),
+      token('B', 17, 'Type',
+          ['declaration']), //token('B', 17, 'dart:core;Type', ['declaration']),
+      token('{', 19, null, null),
+      token('}', 20, null, null),
+      token('mixin', 22, null, null),
+      token('D', 28, 'Type',
+          ['declaration']), //token('D', 28, 'dart:core;Type', ['declaration']),
+      token('on', 30, null, null),
+      token('A', 33, 'dart:core;Type<A>', [
         'reference'
-      ]), //token('A', 'dart:core;Type<$testFileUri;A>', ['reference']),
-      token('implements', null, null),
-      token('B', 'dart:core;Type<B>', [
+      ]), //token('A', 33, 'dart:core;Type<$testFileUri;A>', ['reference']),
+      token('implements', 35, null, null),
+      token('B', 46, 'dart:core;Type<B>', [
         'reference'
       ]), //token('B', 'dart:core;Type<$testFileUri;B>', ['reference']),
-      token('{', null, null),
-      token('}', null, null),
+      token('{', 48, null, null),
+      token('}', 49, null, null),
     ]);
   }
 
@@ -1184,25 +1191,25 @@
   return p;
 }
 ''', [
-      token('int', 'dart:core;Type<int>', [
+      token('int', 0, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('f', 'int Function(int)', [
+      ]), //token('int', 0, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('f', 4, 'int Function(int)', [
         'declaration'
-      ]), //token('f', 'dart:core;int Function(dart:core;int)', ['declaration']),
-      token('(', null, null),
-      token('int', 'dart:core;Type<int>', [
+      ]), //token('f', 4, 'dart:core;int Function(dart:core;int)', ['declaration']),
+      token('(', 5, null, null),
+      token('int', 6, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('p', 'int',
-          ['declaration']), //token('p', 'dart:core;int', ['declaration']),
-      token(')', null, null),
-      token('{', null, null),
-      token('return', null, null),
-      token('p', 'int',
-          ['reference']), //token('p', 'dart:core;int', ['reference']),
-      token(';', null, null),
-      token('}', null, null),
+      ]), //token('int', 6, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('p', 10, 'int',
+          ['declaration']), //token('p', 10, 'dart:core;int', ['declaration']),
+      token(')', 11, null, null),
+      token('{', 13, null, null),
+      token('return', 17, null, null),
+      token('p', 24, 'int',
+          ['reference']), //token('p', 24, 'dart:core;int', ['reference']),
+      token(';', 25, null, null),
+      token('}', 27, null, null),
     ]);
   }
 
@@ -1211,17 +1218,19 @@
 /// Doc comment [x] with reference.
 int x;
 ''', [
-      token('int', 'dart:core;Type<int>', [
+      token('int', 36, 'dart:core;Type<int>', [
         'reference'
-      ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
-      token('x', 'int',
-          ['declaration']), //token('x', 'dart:core;int', ['declaration']),
-      token(';', null, null),
+      ]), //token('int', 36, 'dart:core;Type<dart:core;int>', ['reference']),
+      token('x', 40, 'int',
+          ['declaration']), //token('x', 40, 'dart:core;int', ['declaration']),
+      token(';', 41, null, null),
     ]);
   }
 
-  TokenDetails token(String lexeme, String type, List<String> kinds) {
-    return new TokenDetails(lexeme, type: type, validElementKinds: kinds);
+  TokenDetails token(
+      String lexeme, int offset, String type, List<String> kinds) {
+    return new TokenDetails(lexeme, offset,
+        type: type, validElementKinds: kinds);
   }
 
   void _compareTokens(List<Map<String, dynamic>> actualTokens,
@@ -1237,6 +1246,11 @@
             'expected "${expected.lexeme}", '
             'actual "${actual['lexeme']}"');
       }
+      if (actual['offset'] != expected.offset) {
+        errors.add('Offset at $i: ("${expected.lexeme}"): '
+            'expected "${expected.offset}", '
+            'actual "${actual['offset']}"');
+      }
       if (actual['type'] != expected.type) {
         errors.add('Type at $i ("${expected.lexeme}"): '
             'expected "${expected.type}", '
@@ -1284,3 +1298,4 @@
     return new Future.value();
   }
 }
+
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 22a7245..37bb83e 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -44,9 +44,6 @@
     List<AnalysisErrorFixes> errorFixes =
         await _getFixesAt('Completer<String>');
     expect(errorFixes, hasLength(1));
-    AnalysisError error = errorFixes[0].error;
-    expect(error.severity, AnalysisErrorSeverity.ERROR);
-    expect(error.type, AnalysisErrorType.STATIC_WARNING);
     List<SourceChange> fixes = errorFixes[0].fixes;
     expect(fixes, hasLength(3));
     expect(fixes[0].message, matches('Import library'));
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index ae82a71..20ee12c 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -82,6 +82,7 @@
 - [x] server.setSubscriptions
 - [ ] server.connected
 - [ ] server.error
+- [ ] server.log
 - [x] server.status
 
 ## analytics domain
diff --git a/pkg/analysis_server/test/integration/linter/lint_names_test.dart b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
index 929a9c0..b6ebf92 100644
--- a/pkg/analysis_server/test/integration/linter/lint_names_test.dart
+++ b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
@@ -30,11 +30,11 @@
   /// Ensure server lint name representations correspond w/ actual lint rules.
   /// See, e.g., https://dart-review.googlesource.com/c/sdk/+/95743.
   group('lint_names', () {
-    var fixFileContents = new File(path.join(pathPrefix, 'lib', 'src',
-            'services', 'correction', 'fix_internal.dart'))
+    var fixFileContents = new File(path.join(
+            pathPrefix, 'lib', 'src', 'services', 'linter', 'lint_names.dart'))
         .readAsStringSync();
     var parser = new CompilationUnitParser();
-    var cu = parser.parse(contents: fixFileContents, name: 'fix_internal.dart');
+    var cu = parser.parse(contents: fixFileContents, name: 'lint_names.dart');
     var lintNamesClass = cu.declarations
         .firstWhere((m) => m is ClassDeclaration && m.name.name == 'LintNames');
 
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index 3516f8b..1440fe3 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -135,6 +135,20 @@
   StreamController<ServerErrorParams> _onServerError;
 
   /**
+   * The stream of entries describing events happened in the server.
+   *
+   * Parameters
+   *
+   * entry: ServerLogEntry
+   */
+  Stream<ServerLogParams> onServerLog;
+
+  /**
+   * Stream controller for [onServerLog].
+   */
+  StreamController<ServerLogParams> _onServerLog;
+
+  /**
    * Reports the current status of the server. Parameters are omitted if there
    * has been no change in the status represented by that parameter.
    *
@@ -2739,6 +2753,8 @@
     onServerConnected = _onServerConnected.stream.asBroadcastStream();
     _onServerError = new StreamController<ServerErrorParams>(sync: true);
     onServerError = _onServerError.stream.asBroadcastStream();
+    _onServerLog = new StreamController<ServerLogParams>(sync: true);
+    onServerLog = _onServerLog.stream.asBroadcastStream();
     _onServerStatus = new StreamController<ServerStatusParams>(sync: true);
     onServerStatus = _onServerStatus.stream.asBroadcastStream();
     _onAnalysisAnalyzedFiles =
@@ -2815,6 +2831,11 @@
         _onServerError
             .add(new ServerErrorParams.fromJson(decoder, 'params', params));
         break;
+      case "server.log":
+        outOfTestExpect(params, isServerLogParams);
+        _onServerLog
+            .add(new ServerLogParams.fromJson(decoder, 'params', params));
+        break;
       case "server.status":
         outOfTestExpect(params, isServerStatusParams);
         _onServerStatus
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 358108e..61edec1 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1704,13 +1704,41 @@
 ]);
 
 /**
+ * ServerLogEntry
+ *
+ * {
+ *   "time": int
+ *   "kind": ServerLogEntryKind
+ *   "data": String
+ * }
+ */
+final Matcher isServerLogEntry = new LazyMatcher(() => new MatchesJsonObject(
+    "ServerLogEntry",
+    {"time": isInt, "kind": isServerLogEntryKind, "data": isString}));
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ *   NOTIFICATION
+ *   RAW
+ *   REQUEST
+ *   RESPONSE
+ * }
+ */
+final Matcher isServerLogEntryKind = new MatchesEnum(
+    "ServerLogEntryKind", ["NOTIFICATION", "RAW", "REQUEST", "RESPONSE"]);
+
+/**
  * ServerService
  *
  * enum {
+ *   LOG
  *   STATUS
  * }
  */
-final Matcher isServerService = new MatchesEnum("ServerService", ["STATUS"]);
+final Matcher isServerService =
+    new MatchesEnum("ServerService", ["LOG", "STATUS"]);
 
 /**
  * SourceChange
@@ -1767,11 +1795,13 @@
  *   "lexeme": String
  *   "type": optional String
  *   "validElementKinds": optional List<String>
+ *   "offset": int
  * }
  */
 final Matcher isTokenDetails = new LazyMatcher(() => new MatchesJsonObject(
         "TokenDetails", {
-      "lexeme": isString
+      "lexeme": isString,
+      "offset": isInt
     }, optionalFields: {
       "type": isString,
       "validElementKinds": isListOf(isString)
@@ -3511,6 +3541,16 @@
     new MatchesJsonObject("server.getVersion result", {"version": isString}));
 
 /**
+ * server.log params
+ *
+ * {
+ *   "entry": ServerLogEntry
+ * }
+ */
+final Matcher isServerLogParams = new LazyMatcher(() =>
+    new MatchesJsonObject("server.log params", {"entry": isServerLogEntry}));
+
+/**
  * server.setSubscriptions params
  *
  * {
diff --git a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
index 1e42d22..2439e91 100644
--- a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
@@ -26,6 +26,17 @@
     super.setUp();
   }
 
+  test_extension() async {
+    addTestSource('''
+extension E on int {}
+void f() {
+  E.a^
+}
+''');
+    await computeSuggestions();
+    assertNoSuggestions();
+  }
+
   test_extensionOverride_doesNotMatch() async {
     addTestSource('''
 extension E on int {
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index b4d1d0c..c42a1b6 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -174,6 +174,44 @@
         Keyword.WHILE
       ];
 
+  List<Keyword> get statementStartInSwitchCaseInClass => [
+        Keyword.ASSERT,
+        Keyword.BREAK,
+        Keyword.CONST,
+        Keyword.DO,
+        Keyword.FINAL,
+        Keyword.FOR,
+        Keyword.IF,
+        Keyword.NEW,
+        Keyword.RETURN,
+        Keyword.SUPER,
+        Keyword.THIS,
+        Keyword.SWITCH,
+        Keyword.THROW,
+        Keyword.TRY,
+        Keyword.VAR,
+        Keyword.VOID,
+        Keyword.WHILE
+      ];
+
+  List<Keyword> get statementStartInSwitchCaseOutsideClass => [
+        Keyword.ASSERT,
+        Keyword.BREAK,
+        Keyword.CONST,
+        Keyword.DO,
+        Keyword.FINAL,
+        Keyword.FOR,
+        Keyword.IF,
+        Keyword.NEW,
+        Keyword.RETURN,
+        Keyword.SWITCH,
+        Keyword.THROW,
+        Keyword.TRY,
+        Keyword.VAR,
+        Keyword.VOID,
+        Keyword.WHILE
+      ];
+
   List<Keyword> get statementStartInSwitchInClass => [
         Keyword.ASSERT,
         Keyword.BREAK,
@@ -1983,6 +2021,18 @@
         relevance: DART_RELEVANCE_HIGH);
   }
 
+  test_switch_statement_case_break_insideClass() async {
+    addTestSource('class A{foo() {switch(1) {case 1: b^}}}');
+    await computeSuggestions();
+    assertSuggestKeywords(statementStartInSwitchCaseInClass);
+  }
+
+  test_switch_statement_case_break_outsideClass() async {
+    addTestSource('foo() {switch(1) {case 1: b^}}');
+    await computeSuggestions();
+    assertSuggestKeywords(statementStartInSwitchCaseOutsideClass);
+  }
+
   test_switch_statement_insideClass() async {
     addTestSource('class A{foo() {switch(1) {case 1:^}}}');
     await computeSuggestions();
@@ -2158,6 +2208,14 @@
       super.statementStartInLoopOutsideClass..add(Keyword.LATE);
 
   @override
+  List<Keyword> get statementStartInSwitchCaseInClass =>
+      super.statementStartInSwitchCaseInClass..add(Keyword.LATE);
+
+  @override
+  List<Keyword> get statementStartInSwitchCaseOutsideClass =>
+      super.statementStartInSwitchCaseOutsideClass..add(Keyword.LATE);
+
+  @override
   List<Keyword> get statementStartInSwitchInClass =>
       super.statementStartInSwitchInClass..add(Keyword.LATE);
 
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
index e13ad70..cfc022f 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -11,7 +12,8 @@
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(LibraryMemberContributorTest);
+//    defineReflectiveTests(LibraryMemberContributorTest);
+    defineReflectiveTests(LibraryMemberContributorWithExtensionMethodsTest);
   });
 }
 
@@ -280,3 +282,30 @@
     assertNoSuggestions();
   }
 }
+
+@reflectiveTest
+class LibraryMemberContributorWithExtensionMethodsTest
+    extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new LibraryMemberContributor();
+  }
+
+  @override
+  void setupResourceProvider() {
+    super.setupResourceProvider();
+    createAnalysisOptionsFile(experiments: [EnableString.extension_methods]);
+  }
+
+  test_extension() async {
+    // SimpleIdentifier  PrefixedIdentifier  ExpressionStatement
+    addSource('/home/test/lib/b.dart', '''
+extension MyExt on int {}
+''');
+    addTestSource('''
+        import "b.dart" as b;
+        main() {b.^}''');
+    await computeSuggestions();
+    assertSuggest('MyExt');
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
index 1d3e804..1faf68d 100644
--- a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/static_member_contributor.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -12,6 +13,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(StaticMemberContributorTest);
+    defineReflectiveTests(StaticMemberContributorWithExtensionMethodsTest);
   });
 }
 
@@ -304,3 +306,32 @@
     assertNotSuggested('==');
   }
 }
+
+@reflectiveTest
+class StaticMemberContributorWithExtensionMethodsTest
+    extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new StaticMemberContributor();
+  }
+
+  @override
+  void setupResourceProvider() {
+    super.setupResourceProvider();
+    createAnalysisOptionsFile(experiments: [EnableString.extension_methods]);
+  }
+
+  test_extension() async {
+    addTestSource('''
+extension E on Object {
+  static int i;
+  static String s;
+}
+main() {E.^}
+''');
+    await computeSuggestions();
+    assertNotSuggested('E');
+    assertSuggestField('i', 'int');
+    assertSuggestField('s', 'String');
+  }
+}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index 5725680..4d8e897 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -6,6 +6,7 @@
 import 'dart:convert';
 
 import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/services/refactoring/extract_local.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -90,9 +91,11 @@
 
   test_checkInitialConditions_namePartOfDeclaration_function() async {
     await indexTestUnit('''
-void main() {}
+void main() {
+  void foo() {}
+}
 ''');
-    _createRefactoringWithSuffix('main', '()');
+    _createRefactoringWithSuffix('foo', '()');
     // check conditions
     RefactoringStatus status = await refactoring.checkAllConditions();
     assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
@@ -734,6 +737,23 @@
     expect(refactoring.isAvailable(), isTrue);
   }
 
+  test_lint_prefer_final_locals() async {
+    createAnalysisOptionsFile(lints: [LintNames.prefer_final_locals]);
+    await indexTestUnit('''
+main() {
+  print(1 + 2);
+}
+''');
+    _createRefactoringForString('1 + 2');
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+main() {
+  final res = 1 + 2;
+  print(res);
+}
+''');
+  }
+
   test_occurrences_differentName_samePrefix() async {
     await indexTestUnit('''
 void main(A a) {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
new file mode 100644
index 0000000..c5db8e1
--- /dev/null
+++ b/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
@@ -0,0 +1,338 @@
+// 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/status.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'abstract_rename.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RenameExtensionMemberTest);
+  });
+}
+
+@reflectiveTest
+class RenameExtensionMemberTest extends RenameRefactoringTest {
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_checkFinalConditions_hasMember_MethodElement() async {
+    await indexTestUnit('''
+extension E on int {
+  test() {}
+  newName() {} // existing
+}
+''');
+    createRenameRefactoringAtString('test() {}');
+    // check status
+    refactoring.newName = 'newName';
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Extension 'E' already declares method with name 'newName'.",
+        expectedContextSearch: 'newName() {} // existing');
+  }
+
+  test_checkFinalConditions_OK_dropSuffix() async {
+    await indexTestUnit(r'''
+extension E on int {
+  void testOld() {}
+}
+''');
+    createRenameRefactoringAtString('testOld() {}');
+    // check status
+    refactoring.newName = 'test';
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
+  }
+
+  test_checkFinalConditions_shadowed_byLocalFunction_inExtension() async {
+    await indexTestUnit('''
+extension E on int {
+  test() {}
+  main() {
+    newName() {}
+    test(); // marker
+  }
+}
+''');
+    createRenameRefactoringAtString('test() {}');
+    // check status
+    refactoring.newName = 'newName';
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+      status,
+      RefactoringProblemSeverity.ERROR,
+      expectedMessage:
+          "Usage of renamed method will be shadowed by function 'newName'.",
+      expectedContextSearch: 'test(); // marker',
+    );
+  }
+
+  test_checkFinalConditions_shadowed_byLocalVariable_inExtension() async {
+    await indexTestUnit('''
+extension E on int {
+  test() {}
+  main() {
+    var newName;
+    test(); // marker
+  }
+}
+''');
+    createRenameRefactoringAtString('test() {}');
+    // check status
+    refactoring.newName = 'newName';
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+      status,
+      RefactoringProblemSeverity.ERROR,
+      expectedMessage:
+          "Usage of renamed method will be shadowed by local variable 'newName'.",
+      expectedContextSearch: 'test(); // marker',
+    );
+  }
+
+  test_checkFinalConditions_shadowed_byParameter_inExtension() async {
+    await indexTestUnit('''
+extension E on int {
+  test() {}
+  main(newName) {
+    test(); // marker
+  }
+}
+''');
+    createRenameRefactoringAtString('test() {}');
+    // check status
+    refactoring.newName = 'newName';
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+      status,
+      RefactoringProblemSeverity.ERROR,
+      expectedMessage:
+          "Usage of renamed method will be shadowed by parameter 'newName'.",
+      expectedContextSearch: 'test(); // marker',
+    );
+  }
+
+  test_checkInitialConditions_operator() async {
+    await indexTestUnit('''
+extension E on int {
+  operator -(other) => null;
+}
+''');
+    createRenameRefactoringAtString('-(other)');
+    // check status
+    refactoring.newName = 'newName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
+  }
+
+  test_checkNewName_FieldElement() async {
+    await indexTestUnit('''
+extension E on int {
+  int get test => 0;
+}
+''');
+    createRenameRefactoringAtString('test =>');
+    // null
+    refactoring.newName = null;
+    assertRefactoringStatus(
+      refactoring.checkNewName(),
+      RefactoringProblemSeverity.FATAL,
+      expectedMessage: "Field name must not be null.",
+    );
+
+    // OK
+    refactoring.newName = 'newName';
+    assertRefactoringStatusOK(refactoring.checkNewName());
+  }
+
+  test_checkNewName_MethodElement() async {
+    await indexTestUnit('''
+extension E on int {
+  void test() {}
+}
+''');
+    createRenameRefactoringAtString('test() {}');
+
+    // null
+    refactoring.newName = null;
+    assertRefactoringStatus(
+      refactoring.checkNewName(),
+      RefactoringProblemSeverity.FATAL,
+      expectedMessage: "Method name must not be null.",
+    );
+
+    // empty
+    refactoring.newName = '';
+    assertRefactoringStatus(
+      refactoring.checkNewName(),
+      RefactoringProblemSeverity.FATAL,
+      expectedMessage: "Method name must not be empty.",
+    );
+
+    // same
+    refactoring.newName = 'test';
+    assertRefactoringStatus(
+      refactoring.checkNewName(),
+      RefactoringProblemSeverity.FATAL,
+      expectedMessage: "The new name must be different than the current name.",
+    );
+
+    // OK
+    refactoring.newName = 'newName';
+    assertRefactoringStatusOK(refactoring.checkNewName());
+  }
+
+  test_createChange_MethodElement_instance() async {
+    await indexTestUnit('''
+class A {}
+
+extension E on A {
+  test() {} // marker
+}
+
+main() {
+  var a = A();
+  a.test();
+  E(a).test();
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test() {} // marker');
+    expect(refactoring.refactoringName, 'Rename Method');
+    expect(refactoring.elementKindName, 'method');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+class A {}
+
+extension E on A {
+  newName() {} // marker
+}
+
+main() {
+  var a = A();
+  a.newName();
+  E(a).newName();
+}
+''');
+  }
+
+  test_createChange_PropertyAccessorElement_getter() async {
+    await indexTestUnit('''
+extension E on int {
+  get test {} // marker
+  set test(x) {}
+  main() {
+    test;
+    test = 1;
+  }
+}
+main() {
+  0.test;
+  0.test = 2;
+  
+  E(0).test;
+  E(0).test = 3;
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test {} // marker');
+    expect(refactoring.refactoringName, 'Rename Field');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+extension E on int {
+  get newName {} // marker
+  set newName(x) {}
+  main() {
+    newName;
+    newName = 1;
+  }
+}
+main() {
+  0.newName;
+  0.newName = 2;
+  
+  E(0).newName;
+  E(0).newName = 3;
+}
+''');
+  }
+
+  test_createChange_PropertyAccessorElement_setter() async {
+    await indexTestUnit('''
+extension E on int {
+  get test {}
+  set test(x) {} // marker
+  main() {
+    test;
+    test = 1;
+  }
+}
+main() {
+  0.test;
+  0.test = 2;
+  
+  E(0).test;
+  E(0).test = 3;
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test(x) {} // marker');
+    expect(refactoring.refactoringName, 'Rename Field');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+extension E on int {
+  get newName {}
+  set newName(x) {} // marker
+  main() {
+    newName;
+    newName = 1;
+  }
+}
+main() {
+  0.newName;
+  0.newName = 2;
+  
+  E(0).newName;
+  E(0).newName = 3;
+}
+''');
+  }
+
+  test_createChange_TypeParameterElement() async {
+    await indexTestUnit('''
+extension E<Test> on int {
+  Test get g1 => null;
+  List<Test> get g2 => null;
+  Test m(Test p) => null;
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('Test> on int {');
+    expect(refactoring.refactoringName, 'Rename Type Parameter');
+    expect(refactoring.elementKindName, 'type parameter');
+    expect(refactoring.oldName, 'Test');
+    refactoring.newName = 'NewName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+extension E<NewName> on int {
+  NewName get g1 => null;
+  List<NewName> get g2 => null;
+  NewName m(NewName p) => null;
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/services/refactoring/test_all.dart b/pkg/analysis_server/test/services/refactoring/test_all.dart
index a63865d..17ce7af 100644
--- a/pkg/analysis_server/test/services/refactoring/test_all.dart
+++ b/pkg/analysis_server/test/services/refactoring/test_all.dart
@@ -15,6 +15,7 @@
 import 'naming_conventions_test.dart' as naming_conventions_test;
 import 'rename_class_member_test.dart' as rename_class_member_test;
 import 'rename_constructor_test.dart' as rename_constructor_test;
+import 'rename_extension_member_test.dart' as rename_extension_member_test;
 import 'rename_import_test.dart' as rename_import_test;
 import 'rename_label_test.dart' as rename_label_test;
 import 'rename_library_test.dart' as rename_library_test;
@@ -35,6 +36,7 @@
     naming_conventions_test.main();
     rename_class_member_test.main();
     rename_constructor_test.main();
+    rename_extension_member_test.main();
     rename_import_test.main();
     rename_label_test.main();
     rename_library_test.main();
diff --git a/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart b/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
index bda2825..4dbd8be 100644
--- a/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
@@ -38,6 +38,18 @@
     _check(HighlightRegionType.BUILT_IN, 'on');
   }
 
+  test_methodInvocation_ofExtensionOverride_unresolved() async {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    await _computeHighlights('''
+extension E on int {}
+
+main() {
+  E(0).foo();
+}
+''', hasErrors: true);
+    _check(HighlightRegionType.IDENTIFIER_DEFAULT, 'foo');
+  }
+
   void _check(HighlightRegionType expectedType, String expectedText) {
     for (var region in highlights) {
       if (region.type == expectedType) {
@@ -52,11 +64,20 @@
     fail('Expected region of type $expectedType with text "$expectedText"');
   }
 
-  Future<void> _computeHighlights(String content) async {
+  Future<void> _computeHighlights(
+    String content, {
+    bool hasErrors = false,
+  }) async {
     this.content = content;
     newFile(sourcePath, content: content);
     ResolvedUnitResult result = await session.getResolvedUnit(sourcePath);
-    expect(result.errors, hasLength(0));
+
+    if (hasErrors) {
+      expect(result.errors, isNotEmpty);
+    } else {
+      expect(result.errors, isEmpty);
+    }
+
     DartUnitHighlightsComputer2 computer =
         new DartUnitHighlightsComputer2(result.unit);
     highlights = computer.compute();
diff --git a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
index ab5d0ab..bdba0de 100644
--- a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
@@ -38,6 +38,18 @@
     _check(HighlightRegionType.BUILT_IN, 'on');
   }
 
+  test_methodInvocation_ofExtensionOverride_unresolved() async {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    await _computeHighlights('''
+extension E on int {}
+
+main() {
+  E(0).foo();
+}
+''', hasErrors: true);
+    _check(HighlightRegionType.IDENTIFIER_DEFAULT, 'foo');
+  }
+
   void _check(HighlightRegionType expectedType, String expectedText) {
     for (var region in highlights) {
       if (region.type == expectedType) {
@@ -52,11 +64,20 @@
     fail('Expected region of type $expectedType with text "$expectedText"');
   }
 
-  Future<void> _computeHighlights(String content) async {
+  Future<void> _computeHighlights(
+    String content, {
+    bool hasErrors = false,
+  }) async {
     this.content = content;
     newFile(sourcePath, content: content);
     ResolvedUnitResult result = await session.getResolvedUnit(sourcePath);
-    expect(result.errors, hasLength(0));
+
+    if (hasErrors) {
+      expect(result.errors, isNotEmpty);
+    } else {
+      expect(result.errors, isEmpty);
+    }
+
     DartUnitHighlightsComputer computer =
         new DartUnitHighlightsComputer(result.unit);
     highlights = computer.compute();
diff --git a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
index a6f62cf..6e8af8e 100644
--- a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
@@ -100,6 +100,10 @@
   },
   "parameterNames": [],
   "parameterTypes": [],
+  "relevanceTags": [
+    "package:test/a.dart::A",
+    "a"
+  ],
   "requiredParameterCount": 0
 }
 ''');
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index 824d864..e6704f8 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -300,6 +300,26 @@
 ''');
   }
 
+  test_relevanceTags_location_initializer() async {
+    addTestFile(r'''
+int v = // ref;
+''');
+
+    var results = await _getSuggestions(
+      testFile,
+      testCode.indexOf(' // ref'),
+    );
+
+    assertJsonText(results.includedSuggestionRelevanceTags, r'''
+[
+  {
+    "tag": "dart:core::int",
+    "relevanceBoost": 10
+  }
+]
+''');
+  }
+
   test_relevanceTags_location_listLiteral() async {
     addTestFile(r'''
 main() {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
index 7019111..736d455 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -19,6 +20,17 @@
   @override
   AssistKind get kind => DartAssistKind.ADD_TYPE_ANNOTATION;
 
+  test_classField_final_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.always_specify_types]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+class A {
+  /*caret*/final f = 0;
+}
+''');
+    await assertNoAssist();
+  }
+
   test_classField_final() async {
     await resolveTestUnit('''
 class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
index b13e269..eb40c88 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -90,6 +91,22 @@
 ''');
   }
 
+  test_onText_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.slash_for_doc_comments]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+class A {
+  /**
+   * AAAAAAA [int] AAAAAAA
+   * BBBBBBBB BBBB BBBB
+   * CCC [A] CCCCCCCCCCC
+   */
+  mmm() {}
+}
+''');
+    await assertNoAssist();
+  }
+
   test_onText_hasFirstLine() async {
     await resolveTestUnit('''
 class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
index cb7e2e2..c5cb328 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -41,6 +42,20 @@
 ''');
   }
 
+  test_async_noAssistWithLint() async {
+    createAnalysisOptionsFile(
+        lints: [LintNames.prefer_expression_function_bodies]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+class A {
+  mmm() async {
+    return 42;
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
   test_closure() async {
     await resolveTestUnit('''
 setup(x) {}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
index 0a53680..9d00d66 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -65,6 +66,19 @@
 ''');
   }
 
+  test_mapFromIterable_differentParameterNames_usedInKey_conflictInValue_noAssistWithLint() async {
+    createAnalysisOptionsFile(
+        lints: [LintNames.prefer_for_elements_to_map_fromIterable]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+f(Iterable<int> i) {
+  var k = 3;
+  return Map.fromIt/*caret*/erable(i, key: (k) => k * 2, value: (v) => k);
+}
+''');
+    await assertNoAssist();
+  }
+
   test_mapFromIterable_differentParameterNames_usedInKey_noConflictInValue() async {
     await resolveTestUnit('''
 f(Iterable<int> i) {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
index 5caae77..a718b6a 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -52,6 +53,18 @@
 ''');
   }
 
+  test_conditional_list_noAssistWithLint() async {
+    createAnalysisOptionsFile(
+        lints: [LintNames.prefer_if_elements_to_conditional_expressions]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+f(bool b) {
+  return ['a', b /*caret*/? 'c' : 'd', 'e'];
+}
+''');
+    await assertNoAssist();
+  }
+
   test_conditional_list_withParentheses() async {
     await resolveTestUnit('''
 f(bool b) {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
index 79859c4..b1137ac 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -28,6 +29,15 @@
 ''');
   }
 
+  test_decimal_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.prefer_int_literals]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+const double myDouble = /*caret*/42.0;
+''');
+    await assertNoAssist();
+  }
+
   test_notDouble() async {
     await resolveTestUnit('''
 const double myDouble = /*caret*/42;
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
index 5677205..dfe8b4e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -95,6 +96,18 @@
 ''');
   }
 
+  test_equal_nullOnLeft_noAssistWithLint() async {
+    createAnalysisOptionsFile(lints: [LintNames.prefer_null_aware_operators]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+abstract class A {
+  int m();
+}
+int f(A a) => null == a ? null : a.m();
+''');
+    await assertNoAssist();
+  }
+
   test_equal_nullOnRight() async {
     await resolveTestUnit('''
 abstract class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
index 6e668f3..c22ea1d9 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
@@ -19,6 +19,40 @@
   @override
   AssistKind get kind => DartAssistKind.FLUTTER_WRAP_COLUMN;
 
+  test_controlFlowCollections_if() async {
+    addFlutterPackage();
+    await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+Widget build(bool b) {
+  return Row(
+    children: [
+      Text('aaa'),
+      if (b) /*caret*/Text('bbb'),
+      Text('ccc'),
+    ],
+  );
+}
+''');
+    await assertHasAssist('''
+import 'package:flutter/widgets.dart';
+
+Widget build(bool b) {
+  return Row(
+    children: [
+      Text('aaa'),
+      if (b) Column(
+        children: <Widget>[
+          Text('bbb'),
+        ],
+      ),
+      Text('ccc'),
+    ],
+  );
+}
+''');
+  }
+
   test_coveredByWidget() async {
     addFlutterPackage();
     await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart b/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
index f3e6589..650dfd0 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -355,6 +356,18 @@
 ''');
   }
 
+  test_noAssistWithLint() async {
+    createAnalysisOptionsFile(
+        lints: [LintNames.curly_braces_in_flow_control_structures]);
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+main() {
+  do print/*caret*/(0); while (true);
+}
+''');
+    await assertNoAssist();
+  }
+
   test_while_body_end() async {
     await resolveTestUnit('''
 main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
index 1391007..aee1f1c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
new file mode 100644
index 0000000..8ed3a7f
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package: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(AddConstTest);
+  });
+}
+
+@reflectiveTest
+class AddConstTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_CONST;
+
+  @override
+  String get lintCode => LintNames.prefer_const_constructors;
+
+  test_basic() async {
+    await resolveTestUnit('''
+class C {
+  const C();
+}
+main() {
+  var c = C/*LINT*/();
+}
+''');
+    await assertHasFix('''
+class C {
+  const C();
+}
+main() {
+  var c = const C/*LINT*/();
+}
+''');
+  }
+
+  test_not_present() async {
+    await resolveTestUnit('''
+class C {
+  const C();
+}
+main() {
+  var c = new C/*LINT*/();
+}
+''');
+    // handled by REPLACE_NEW_WITH_CONST
+    await assertNoFix();
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
new file mode 100644
index 0000000..ae04af5
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(AddCurlyBracesTest);
+  });
+}
+
+@reflectiveTest
+class AddCurlyBracesTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_CURLY_BRACES;
+
+  @override
+  String get lintCode => LintNames.curly_braces_in_flow_control_structures;
+
+  // More coverage in the `use_curly_braces_test.dart` assist test.
+  test_do_block() async {
+    await resolveTestUnit('''
+main() {
+  do /*LINT*/print(0); while (true);
+}
+''');
+    await assertHasFix('''
+main() {
+  do {
+    print(0);
+  } while (true);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
index 8a1cf11..229c280 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
index eae5d92..5698974 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
new file mode 100644
index 0000000..a7b406c
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package: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(AddTypeAnnotationTest);
+  });
+}
+
+@reflectiveTest
+class AddTypeAnnotationTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_TYPE_ANNOTATION;
+
+  @override
+  String get lintCode => LintNames.always_specify_types;
+
+  // More coverage in the `add_type_annotation_test.dart` assist test.
+  test_do_block() async {
+    await resolveTestUnit('''
+class A {
+  /*LINT*/final f = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  /*LINT*/final int f = 0;
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
index 553d1e5..0a30962 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
@@ -11,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ChangeToTest);
+    defineReflectiveTests(ChangeToWithExtensionMethodsTest);
   });
 }
 
@@ -19,7 +20,7 @@
   @override
   FixKind get kind => DartFixKind.CHANGE_TO;
 
-  test_undefinedClass_fromImport() async {
+  test_class_fromImport() async {
     await resolveTestUnit('''
 main() {
   Stirng s = 'abc';
@@ -34,7 +35,7 @@
 ''');
   }
 
-  test_undefinedClass_fromThisLibrary() async {
+  test_class_fromThisLibrary() async {
     await resolveTestUnit('''
 class MyClass {}
 main() {
@@ -51,7 +52,7 @@
 ''');
   }
 
-  test_undefinedClass_prefixed() async {
+  test_class_prefixed() async {
     await resolveTestUnit('''
 import 'dart:async' as c;
 main() {
@@ -68,7 +69,7 @@
 ''');
   }
 
-  test_undefinedFunction_fromImport() async {
+  test_function_fromImport() async {
     await resolveTestUnit('''
 main() {
   pritn(0);
@@ -81,7 +82,7 @@
 ''');
   }
 
-  test_undefinedFunction_prefixed_fromImport() async {
+  test_function_prefixed_fromImport() async {
     await resolveTestUnit('''
 import 'dart:core' as c;
 main() {
@@ -96,7 +97,7 @@
 ''');
   }
 
-  test_undefinedFunction_prefixed_ignoreLocal() async {
+  test_function_prefixed_ignoreLocal() async {
     await resolveTestUnit('''
 import 'dart:async' as c;
 main() {
@@ -106,7 +107,7 @@
     await assertNoFix();
   }
 
-  test_undefinedFunction_thisLibrary() async {
+  test_function_thisLibrary() async {
     await resolveTestUnit('''
 myFunction() {}
 main() {
@@ -121,7 +122,7 @@
 ''');
   }
 
-  test_undefinedGetter_hint() async {
+  test_getter_hint() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -142,7 +143,7 @@
 ''');
   }
 
-  test_undefinedGetter_qualified() async {
+  test_getter_qualified() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -161,7 +162,7 @@
 ''');
   }
 
-  test_undefinedGetter_qualified_static() async {
+  test_getter_qualified_static() async {
     await resolveTestUnit('''
 class A {
   static int MY_NAME = 1;
@@ -180,7 +181,7 @@
 ''');
   }
 
-  test_undefinedGetter_unqualified() async {
+  test_getter_unqualified() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -199,7 +200,7 @@
 ''');
   }
 
-  test_undefinedMethod_ignoreOperators() async {
+  test_method_ignoreOperators() async {
     await resolveTestUnit('''
 main(Object object) {
   object.then();
@@ -208,7 +209,7 @@
     await assertNoFix();
   }
 
-  test_undefinedMethod_qualified() async {
+  test_method_qualified() async {
     await resolveTestUnit('''
 class A {
   myMethod() {}
@@ -229,7 +230,7 @@
 ''');
   }
 
-  test_undefinedMethod_unqualified_superClass() async {
+  test_method_unqualified_superClass() async {
     await resolveTestUnit('''
 class A {
   myMethod() {}
@@ -252,7 +253,7 @@
 ''');
   }
 
-  test_undefinedMethod_unqualified_thisClass() async {
+  test_method_unqualified_thisClass() async {
     await resolveTestUnit('''
 class A {
   myMethod() {}
@@ -271,7 +272,7 @@
 ''');
   }
 
-  test_undefinedSetter_hint() async {
+  test_setter_hint() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -292,7 +293,7 @@
 ''');
   }
 
-  test_undefinedSetter_qualified() async {
+  test_setter_qualified() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -311,7 +312,7 @@
 ''');
   }
 
-  test_undefinedSetter_unqualified() async {
+  test_setter_unqualified() async {
     await resolveTestUnit('''
 class A {
   int myField;
@@ -330,3 +331,128 @@
 ''');
   }
 }
+
+@reflectiveTest
+class ChangeToWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CHANGE_TO;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_getter_override() async {
+    await resolveTestUnit('''
+extension E on int {
+  int get myGetter => 0;
+}
+void f() {
+  E(1).myGeter;
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  int get myGetter => 0;
+}
+void f() {
+  E(1).myGetter;
+}
+''');
+  }
+
+  test_getter_static() async {
+    await resolveTestUnit('''
+extension E on int {
+  static int get myGetter => 0;
+}
+void f() {
+  E.myGeter;
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  static int get myGetter => 0;
+}
+void f() {
+  E.myGetter;
+}
+''');
+  }
+
+  test_method_override() async {
+    await resolveTestUnit('''
+extension E on int {
+  int myMethod() => 0;
+}
+void f() {
+  E(1).myMetod();
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  int myMethod() => 0;
+}
+void f() {
+  E(1).myMethod();
+}
+''');
+  }
+
+  test_method_static() async {
+    await resolveTestUnit('''
+extension E on int {
+  static int myMethod() => 0;
+}
+void f() {
+  E.myMetod();
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  static int myMethod() => 0;
+}
+void f() {
+  E.myMethod();
+}
+''');
+  }
+
+  test_setter_override() async {
+    await resolveTestUnit('''
+extension E on int {
+  void set mySetter(int i) {}
+}
+void f() {
+  E(1).mySeter = 0;
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  void set mySetter(int i) {}
+}
+void f() {
+  E(1).mySetter = 0;
+}
+''');
+  }
+
+  test_setter_static() async {
+    await resolveTestUnit('''
+extension E on int {
+  static void set mySetter(int i) {}
+}
+void f() {
+  E.mySeter = 0;
+}
+''');
+    await assertHasFix('''
+extension E on int {
+  static void set mySetter(int i) {}
+}
+void f() {
+  E.mySetter = 0;
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
new file mode 100644
index 0000000..8acb794
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(ConvertDocumentationIntoLineTest);
+  });
+}
+
+@reflectiveTest
+class ConvertDocumentationIntoLineTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_LINE_COMMENT;
+
+  @override
+  String get lintCode => LintNames.slash_for_doc_comments;
+
+  // More coverage in the `convert_to_documentation_line_test.dart` assist test.
+  test_onText() async {
+    await resolveTestUnit('''
+class A {
+  /**
+   * /*LINT*/AAAAAAA [int] AAAAAAA
+   * BBBBBBBB BBBB BBBB
+   * CCC [A] CCCCCCCCCCC
+   */
+  mmm() {}
+}
+''');
+    await assertHasFix('''
+class A {
+  /// /*LINT*/AAAAAAA [int] AAAAAAA
+  /// BBBBBBBB BBBB BBBB
+  /// CCC [A] CCCCCCCCCCC
+  mmm() {}
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
new file mode 100644
index 0000000..6ec1ad1
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(ConvertIntoExpressionBodyTest);
+  });
+}
+
+@reflectiveTest
+class ConvertIntoExpressionBodyTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_INTO_EXPRESSION_BODY;
+
+  @override
+  String get lintCode => LintNames.prefer_expression_function_bodies;
+
+  /// More coverage in the `convert_into_expression_body_test.dart` assist test.
+  test_async() async {
+    await resolveTestUnit('''
+class A {
+  mmm() async { 
+    return 42; /*LINT*/
+  }
+}
+''');
+    await assertHasFix('''
+class A {
+  mmm() async => 42;
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
new file mode 100644
index 0000000..d2a6bd9
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(ConvertToForElementTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToForElementTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_FOR_ELEMENT;
+
+  @override
+  String get lintCode => LintNames.prefer_for_elements_to_map_fromIterable;
+
+  // More coverage in the `convert_to_for_element_line_test.dart` assist test.
+  test_mapFromIterable_differentParameterNames_usedInKey_conflictInValue() async {
+    await resolveTestUnit('''
+f(Iterable<int> i) {
+  var k = 3;
+  return Map.fromIterable/*LINT*/(i, key: (k) => k * 2, value: (v) => k);
+}
+''');
+    await assertHasFix('''
+f(Iterable<int> i) {
+  var k = 3;
+  return { for (var e in i) e * 2 : k };
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
new file mode 100644
index 0000000..c99a0be
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(ConvertToIfElementTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToIfElementTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_IF_ELEMENT;
+
+  @override
+  String get lintCode =>
+      LintNames.prefer_if_elements_to_conditional_expressions;
+
+  // More coverage in the `convert_to_if_element_test.dart` assist test.
+  test_conditional_list() async {
+    await resolveTestUnit('''
+f(bool b) {
+  return ['a', b /*LINT*/? 'c' : 'd', 'e'];
+}
+''');
+    await assertHasFix('''
+f(bool b) {
+  return ['a', if (b) 'c' else 'd', 'e'];
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
new file mode 100644
index 0000000..8c75087
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE 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(ConvertToIntLiteralTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToIntLiteralTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_INT_LITERAL;
+
+  @override
+  String get lintCode => LintNames.prefer_int_literals;
+
+  /// More coverage in the `convert_to_int_literal_test.dart` assist test.
+  test_decimal() async {
+    await resolveTestUnit('''
+const double myDouble = /*LINT*/42.0;
+''');
+    await assertHasFix('''
+const double myDouble = /*LINT*/42;
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
index de9c388..b61d6ef 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
@@ -95,6 +95,44 @@
 ''');
   }
 
+  test_methodInvocation_functionTypedGetter() async {
+    await resolveTestUnit('''
+class A {
+  void Function({int aaa}) get g => null;
+}
+
+main(A a) {
+  a.g(0);
+}
+''');
+    await assertHasFix('''
+class A {
+  void Function({int aaa}) get g => null;
+}
+
+main(A a) {
+  a.g(aaa: 0);
+}
+''');
+  }
+
+  test_methodInvocation_functionTypedVariable() async {
+    await resolveTestUnit('''
+typedef F = void Function({int aaa});
+
+main(F f) {
+  f(0);
+}
+''');
+    await assertHasFix('''
+typedef F = void Function({int aaa});
+
+main(F f) {
+  f(aaa: 0);
+}
+''');
+  }
+
   test_noCompatibleParameter() async {
     await resolveTestUnit('''
 class A {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart
new file mode 100644
index 0000000..3f8d5e6
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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(ConvertToNullAwareTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToNullAwareTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_NULL_AWARE;
+
+  @override
+  String get lintCode => LintNames.prefer_null_aware_operators;
+
+  /// More coverage in the `convert_to_null_aware_test.dart` assist test.
+  test_equal_nullOnLeft() async {
+    await resolveTestUnit('''
+abstract class A {
+  int m();
+}
+int f(A a) => null == a /*LINT*/? null : a.m();
+''');
+    await assertHasFix('''
+abstract class A {
+  int m();
+}
+int f(A a) => a?.m();
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
index 85941b0..e324763 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
@@ -12,6 +12,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(CreateGetterTest);
     defineReflectiveTests(CreateGetterMixinTest);
+    defineReflectiveTests(CreateGetterWithExtensionMethodsTest);
   });
 }
 
@@ -361,3 +362,88 @@
 ''');
   }
 }
+
+@reflectiveTest
+class CreateGetterWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_GETTER;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_internal_instance() async {
+    await resolveTestUnit('''
+extension E on String {
+  int m()  => g;
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  get g => null;
+
+  int m()  => g;
+}
+''');
+  }
+
+  test_internal_static() async {
+    await resolveTestUnit('''
+extension E on String {
+  static int m()  => g;
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static get g => null;
+
+  static int m()  => g;
+}
+''');
+  }
+
+  test_override() async {
+    await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+  int v = E(s).test;
+  print(v);
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  int get test => null;
+}
+
+main(String s) {
+  int v = E(s).test;
+  print(v);
+}
+''');
+  }
+
+  test_static() async {
+    await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+  int v = E.test;
+  print(v);
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static int get test => null;
+}
+
+main(String s) {
+  int v = E.test;
+  print(v);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
index bf502f1..3c76f45 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
@@ -13,6 +13,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(CreateMethodTest);
     defineReflectiveTests(CreateMethodMixinTest);
+    defineReflectiveTests(CreateMethodWithExtensionMethodsTest);
   });
 }
 
@@ -703,3 +704,82 @@
     await assertNoFix();
   }
 }
+
+@reflectiveTest
+class CreateMethodWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_METHOD;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_internal_instance() async {
+    await resolveTestUnit('''
+extension E on String {
+  int m() => n();
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  int m() => n();
+
+  n() {}
+}
+''');
+  }
+
+  test_internal_static() async {
+    await resolveTestUnit('''
+extension E on String {
+  static int m() => n();
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static int m() => n();
+
+  static n() {}
+}
+''');
+  }
+
+  test_override() async {
+    await resolveTestUnit('''
+extension E on String {}
+
+void f() {
+  E('a').m();
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  void m() {}
+}
+
+void f() {
+  E('a').m();
+}
+''');
+  }
+
+  test_static() async {
+    await resolveTestUnit('''
+extension E on String {}
+
+void f() {
+  E.m();
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static void m() {}
+}
+
+void f() {
+  E.m();
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart
new file mode 100644
index 0000000..2edc875
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart
@@ -0,0 +1,387 @@
+// 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:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CreateSetterTest);
+    defineReflectiveTests(CreateSetterMixinTest);
+    defineReflectiveTests(CreateSetterWithExtensionMethodsTest);
+  });
+}
+
+@reflectiveTest
+class CreateSetterMixinTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_SETTER;
+
+  test_qualified_instance() async {
+    await resolveTestUnit('''
+mixin M {
+}
+
+main(M m) {
+  m.test = 0;
+}
+''');
+    await assertHasFix('''
+mixin M {
+  set test(int test) {}
+}
+
+main(M m) {
+  m.test = 0;
+}
+''');
+  }
+
+  test_unqualified_instance_assignmentLhs() async {
+    await resolveTestUnit('''
+mixin M {
+  main() {
+    test = 0;
+  }
+}
+''');
+    await assertHasFix('''
+mixin M {
+  set test(int test) {}
+
+  main() {
+    test = 0;
+  }
+}
+''');
+  }
+
+  test_unqualified_instance_assignmentRhs() async {
+    await resolveTestUnit('''
+mixin M {
+  main() {
+    test;
+  }
+}
+''');
+    await assertNoFix();
+  }
+}
+
+@reflectiveTest
+class CreateSetterTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_SETTER;
+
+  test_getterContext() async {
+    await resolveTestUnit('''
+class A {
+}
+main(A a) {
+  a.test;
+}
+''');
+    await assertNoFix();
+  }
+
+  test_inferredTargetType() async {
+    await resolveTestUnit('''
+class A {
+}
+main(A a) {
+  var x = a;
+  x.test = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  set test(int test) {}
+}
+main(A a) {
+  var x = a;
+  x.test = 0;
+}
+''');
+  }
+
+  test_inSDK() async {
+    await resolveTestUnit('''
+main(List p) {
+  p.foo = 0;
+}
+''');
+    await assertNoFix();
+  }
+
+  test_location_afterLastAccessor() async {
+    await resolveTestUnit('''
+class A {
+  int existingField;
+
+  int get existingGetter => null;
+
+  existingMethod() {}
+}
+main(A a) {
+  a.test = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  int existingField;
+
+  int get existingGetter => null;
+
+  set test(int test) {}
+
+  existingMethod() {}
+}
+main(A a) {
+  a.test = 0;
+}
+''');
+  }
+
+  test_multiLevel() async {
+    await resolveTestUnit('''
+class A {
+}
+class B {
+  A a;
+}
+class C {
+  B b;
+}
+main(C c) {
+  c.b.a.test = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  set test(int test) {}
+}
+class B {
+  A a;
+}
+class C {
+  B b;
+}
+main(C c) {
+  c.b.a.test = 0;
+}
+''');
+  }
+
+  test_qualified_instance() async {
+    await resolveTestUnit('''
+class A {
+}
+main(A a) {
+  a.test = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  set test(int test) {}
+}
+main(A a) {
+  a.test = 0;
+}
+''');
+  }
+
+  test_qualified_instance_differentLibrary() async {
+    addSource('/home/test/lib/other.dart', '''
+/**
+ * A comment to push the offset of the braces for the following class
+ * declaration past the end of the content of the test file. Used to catch an
+ * index out of bounds exception that occurs when using the test source instead
+ * of the target source to compute the location at which to insert the field.
+ */
+class A {
+}
+''');
+
+    await resolveTestUnit('''
+import 'package:test/other.dart';
+
+main(A a) {
+  a.test = 0;
+}
+''');
+
+    await assertHasFix('''
+/**
+ * A comment to push the offset of the braces for the following class
+ * declaration past the end of the content of the test file. Used to catch an
+ * index out of bounds exception that occurs when using the test source instead
+ * of the target source to compute the location at which to insert the field.
+ */
+class A {
+  set test(int test) {}
+}
+''', target: '/home/test/lib/other.dart');
+  }
+
+  test_qualified_instance_dynamicType() async {
+    await resolveTestUnit('''
+class A {
+  B b;
+  void f(p) {
+    b.test = p;
+  }
+}
+class B {
+}
+''');
+    await assertHasFix('''
+class A {
+  B b;
+  void f(p) {
+    b.test = p;
+  }
+}
+class B {
+  set test(test) {}
+}
+''');
+  }
+
+  test_qualified_propagatedType() async {
+    await resolveTestUnit('''
+class A {
+  A get self => this;
+}
+main() {
+  var a = new A();
+  a.self.test = 0;
+}
+''');
+    await assertHasFix('''
+class A {
+  A get self => this;
+
+  set test(int test) {}
+}
+main() {
+  var a = new A();
+  a.self.test = 0;
+}
+''');
+  }
+
+  test_unqualified_instance_assignmentLhs() async {
+    await resolveTestUnit('''
+class A {
+  main() {
+    test = 0;
+  }
+}
+''');
+    await assertHasFix('''
+class A {
+  set test(int test) {}
+
+  main() {
+    test = 0;
+  }
+}
+''');
+  }
+
+  test_unqualified_instance_assignmentRhs() async {
+    await resolveTestUnit('''
+class A {
+  main() {
+    test;
+  }
+}
+''');
+    await assertNoFix();
+  }
+}
+
+@reflectiveTest
+class CreateSetterWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_SETTER;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_internal_instance() async {
+    await resolveTestUnit('''
+extension E on String {
+  int m(int x) => s = x;
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  set s(int s) {}
+
+  int m(int x) => s = x;
+}
+''');
+  }
+
+  test_internal_static() async {
+    await resolveTestUnit('''
+extension E on String {
+  static int m(int x) => s = x;
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static set s(int s) {}
+
+  static int m(int x) => s = x;
+}
+''');
+  }
+
+  test_override() async {
+    await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+  E(s).test = '0';
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  set test(String test) {}
+}
+
+main(String s) {
+  E(s).test = '0';
+}
+''');
+  }
+
+  test_static() async {
+    await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+  E.test = 0;
+}
+''');
+    await assertHasFix('''
+extension E on String {
+  static set test(int test) {}
+}
+
+main(String s) {
+  E.test = 0;
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
index af0bbbe..3e3a04a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
@@ -11,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ImportLibraryPrefixTest);
+    defineReflectiveTests(ImportLibraryPrefixWithExtensionMethodsTest);
   });
 }
 
@@ -55,3 +56,35 @@
 ''');
   }
 }
+
+@reflectiveTest
+class ImportLibraryPrefixWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.IMPORT_LIBRARY_PREFIX;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_withExtension() async {
+    addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on int {
+  static String m() => '';
+}
+''');
+    await resolveTestUnit('''
+import 'lib.dart' as p;
+void f(p.C c) {
+  print(E.m());
+}
+''');
+    await assertHasFix('''
+import 'lib.dart' as p;
+void f(p.C c) {
+  print(p.E.m());
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index 8119ac1..be7b39a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -12,12 +12,52 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ImportLibraryProject1Test);
+    defineReflectiveTests(ImportLibraryProject1WithExtensionMethodsTest);
     defineReflectiveTests(ImportLibraryProject2Test);
+    defineReflectiveTests(ImportLibraryProject2WithExtensionMethodsTest);
     defineReflectiveTests(ImportLibraryProject3Test);
+    defineReflectiveTests(ImportLibraryProject3WithExtensionMethodsTest);
   });
 }
 
 @reflectiveTest
+class ImportLibraryProject1WithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_lib() async {
+    addPackageFile('my_pkg', 'a.dart', '''
+extension E on int {
+  static String m() => '';
+}
+''');
+    newFile('/home/test/pubspec.yaml', content: r'''
+dependencies:
+  my_pkg: any
+''');
+
+    await resolveTestUnit('''
+f() {
+  print(E.m());
+}
+''');
+
+    await assertHasFix('''
+import 'package:my_pkg/a.dart';
+
+f() {
+  print(E.m());
+}
+''', expectedNumberOfFixesForKind: 1);
+  }
+}
+
+@reflectiveTest
 class ImportLibraryProject1Test extends FixProcessorTest {
   @override
   FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
@@ -386,11 +426,8 @@
 ''');
   }
 
-  test_withFunction_identifier() async {
-    addSource('/home/test/lib/lib.dart', '''
-library lib;
-myFunction() {}
-''');
+  test_withFunction_functionTopLevelVariableIdentifier() async {
+    addSource('/home/test/lib/lib.dart', 'var myFunction = () {};');
     await resolveTestUnit('''
 main() {
   myFunction;
@@ -405,8 +442,11 @@
 ''');
   }
 
-  test_withFunction_functionTopLevelVariableIdentifier() async {
-    addSource('/home/test/lib/lib.dart', 'var myFunction = () {};');
+  test_withFunction_identifier() async {
+    addSource('/home/test/lib/lib.dart', '''
+library lib;
+myFunction() {}
+''');
     await resolveTestUnit('''
 main() {
   myFunction;
@@ -488,7 +528,7 @@
 
 class X = Object with Test;
 ''', errorFilter: (error) {
-      return error.errorCode == StaticWarningCode.UNDEFINED_CLASS;
+      return error.errorCode == CompileTimeErrorCode.UNDEFINED_CLASS;
     });
   }
 
@@ -513,6 +553,42 @@
 }
 
 @reflectiveTest
+class ImportLibraryProject2WithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT2;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_lib_src() async {
+    addPackageFile('my_pkg', 'a.dart', "export 'src/b.dart';");
+    addPackageFile('my_pkg', 'src/b.dart', '''
+extension E on int {
+  static String m() => '';
+}
+''');
+    newFile('/home/test/pubspec.yaml', content: r'''
+dependencies:
+  my_pkg: any
+''');
+    await resolveTestUnit('''
+f() {
+  print(E.m());
+}
+''');
+    await assertHasFix('''
+import 'package:my_pkg/a.dart';
+
+f() {
+  print(E.m());
+}
+''');
+  }
+}
+
+@reflectiveTest
 class ImportLibraryProject2Test extends FixProcessorTest {
   @override
   FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT2;
@@ -565,6 +641,37 @@
 }
 
 @reflectiveTest
+class ImportLibraryProject3WithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT3;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_inLibSrc_thisContextRoot() async {
+    addSource('/home/test/lib/src/lib.dart', '''
+extension E on int {
+  static String m() => '';
+}
+''');
+    await resolveTestUnit('''
+f() {
+  print(E.m());
+}
+''');
+    await assertHasFix('''
+import 'package:test/src/lib.dart';
+
+f() {
+  print(E.m());
+}
+''');
+  }
+}
+
+@reflectiveTest
 class ImportLibraryProject3Test extends FixProcessorTest {
   @override
   FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT3;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
index 4f3885f..acf4b72 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
@@ -11,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ImportLibraryShowTest);
+    defineReflectiveTests(ImportLibraryShowWithExtensionMethodsTest);
   });
 }
 
@@ -24,39 +25,92 @@
 class A {}
 class B {}
 ''');
-    await resolveTestUnit('''
+    await resolveTestUnit(r'''
 import 'lib.dart' show A;
 main() {
   A a;
   B b;
-  print('\$a \$b');
+  print('$a $b');
 }
 ''');
-    await assertHasFix('''
+    await assertHasFix(r'''
 import 'lib.dart' show A, B;
 main() {
   A a;
   B b;
-  print('\$a \$b');
+  print('$a $b');
 }
 ''');
   }
 
   test_sdk() async {
-    await resolveTestUnit('''
+    await resolveTestUnit(r'''
 import 'dart:collection' show HashMap;
 main() {
   HashMap s = null;
   LinkedHashMap f = null;
-  print('\$s \$f');
+  print('$s $f');
 }
 ''');
-    await assertHasFix('''
+    await assertHasFix(r'''
 import 'dart:collection' show HashMap, LinkedHashMap;
 main() {
   HashMap s = null;
   LinkedHashMap f = null;
-  print('\$s \$f');
+  print('$s $f');
+}
+''');
+  }
+}
+
+@reflectiveTest
+class ImportLibraryShowWithExtensionMethodsTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.IMPORT_LIBRARY_SHOW;
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_override_samePackage() async {
+    addSource('/home/test/lib/lib.dart', '''
+class A {}
+extension E on int {
+  String m() => '';
+}
+''');
+    await resolveTestUnit(r'''
+import 'lib.dart' show A;
+void f(A a) {
+  print('$a ${E(3).m()}');
+}
+''');
+    await assertHasFix(r'''
+import 'lib.dart' show A, E;
+void f(A a) {
+  print('$a ${E(3).m()}');
+}
+''');
+  }
+
+  test_static_samePackage() async {
+    addSource('/home/test/lib/lib.dart', '''
+class A {}
+extension E on int {
+  static String m() => '';
+}
+''');
+    await resolveTestUnit(r'''
+import 'lib.dart' show A;
+void f(A a) {
+  print('$a ${E.m()}');
+}
+''');
+    await assertHasFix(r'''
+import 'lib.dart' show A, E;
+void f(A a) {
+  print('$a ${E.m()}');
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
index 31bc18d..1336479 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart
new file mode 100644
index 0000000..3c210a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.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(MakeVariableNotFinalTest);
+  });
+}
+
+@reflectiveTest
+class MakeVariableNotFinalTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.MAKE_VARIABLE_NOT_FINAL;
+
+  test_hasType() async {
+    await resolveTestUnit('''
+main() {
+  final int fff = 1;
+  fff = 2;
+  print(fff);
+}
+''');
+    await assertHasFix('''
+main() {
+  int fff = 1;
+  fff = 2;
+  print(fff);
+}
+''');
+  }
+
+  test_noType() async {
+    await resolveTestUnit('''
+main() {
+  final fff = 1;
+  fff = 2;
+  print(fff);
+}
+''');
+    await assertHasFix('''
+main() {
+  var fff = 1;
+  fff = 2;
+  print(fff);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
index 6121171..d275386 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
index 0f1f928..3cd7576 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
index b5784b8..317e9a1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
index 3030ea2..93f33be 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
index 1019af5..f65b70e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
index 18a278c..74e9b9f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
index b686d62..5266d462 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
index b48e7d8..4dfe93a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
index 666a59c..730249c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
index 5ea13d4..d9c73d5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
index 54deb8b..5517927 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
index 440b948..a42b897 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
index b1cad87..a29dacf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
index 45f6677..8afc1c4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
index 85e0bb6..2bf65bf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
index 77fa5a7..9c05196 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
new file mode 100644
index 0000000..e59a3a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package: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(ReplaceNewWithConstTest);
+  });
+}
+
+@reflectiveTest
+class ReplaceNewWithConstTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.REPLACE_NEW_WITH_CONST;
+
+  @override
+  String get lintCode => LintNames.prefer_const_constructors;
+
+  test_basic() async {
+    await resolveTestUnit('''
+class C {
+  const C();
+}
+main() {
+  var c = new C/*LINT*/();
+}
+''');
+    await assertHasFix('''
+class C {
+  const C();
+}
+main() {
+  var c = const C/*LINT*/();
+}
+''');
+  }
+
+  test_not_present() async {
+    await resolveTestUnit('''
+class C {
+  const C();
+}
+main() {
+  var c = C/*LINT*/();
+}
+''');
+    // handled by ADD_CONST
+    await assertNoFix();
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
index 4ada2dd..1f733fe 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
index 93cae94..bac5617 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
index e5baaec..32be5b7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
index 6dfc38c..82152f7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
index ef13aa9..8548cc2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
index 9b621d9..91c556e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
index ccc757a..f246605 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
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 de8cd2a..67efef9 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
@@ -6,6 +6,8 @@
 
 import 'add_async_test.dart' as add_async;
 import 'add_await_test.dart' as add_await;
+import 'add_const_test.dart' as add_const;
+import 'add_curly_braces_test.dart' as add_curly_braces;
 import 'add_explicit_cast_test.dart' as add_explicit_cast;
 import 'add_field_formal_parameters_test.dart' as add_field_formal_parameters;
 import 'add_missing_enum_case_clauses_test.dart'
@@ -23,6 +25,7 @@
 import 'add_static_test.dart' as add_static;
 import 'add_super_constructor_invocation_test.dart'
     as add_super_constructor_invocation;
+import 'add_type_annotation_test.dart' as add_type_annotation;
 import 'analysis_options/test_all.dart' as analysis_options;
 import 'change_argument_name_test.dart' as change_argument_name;
 import 'change_to_nearest_precise_value_test.dart'
@@ -30,9 +33,16 @@
 import 'change_to_static_access_test.dart' as change_to_static_access;
 import 'change_to_test.dart' as change_to;
 import 'change_type_annotation_test.dart' as change_type_annotation;
+import 'convert_documentation_into_line_test.dart'
+    as convert_documentation_into_line;
 import 'convert_flutter_child_test.dart' as convert_flutter_child;
 import 'convert_flutter_children_test.dart' as convert_flutter_children;
+import 'convert_into_expression_body_test.dart' as convert_into_expression_body;
+import 'convert_to_for_element_test.dart' as convert_to_for_element;
+import 'convert_to_if_element_test.dart' as convert_to_if_element;
+import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
 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 'create_class_test.dart' as create_class;
 import 'create_constructor_for_final_fields_test.dart'
     as create_constructor_for_final_field;
@@ -47,6 +57,7 @@
 import 'create_missing_overrides_test.dart' as create_missing_overrides;
 import 'create_mixin_test.dart' as create_mixin;
 import 'create_no_such_method_test.dart' as create_no_such_method;
+import 'create_setter_test.dart' as create_setter;
 import 'extend_class_for_mixin_test.dart' as extend_class_for_mixin;
 import 'fix_test.dart' as fix;
 import 'import_async_test.dart' as import_async;
@@ -58,6 +69,7 @@
 import 'make_class_abstract_test.dart' as make_class_abstract;
 import 'make_field_not_final_test.dart' as make_field_not_final;
 import 'make_final_test.dart' as make_final;
+import 'make_variable_not_final_test.dart' as make_variable_not_final;
 import 'move_type_arguments_to_class_test.dart' as move_type_arguments_to_class;
 import 'remove_annotation_test.dart' as remove_annotation;
 import 'remove_await_test.dart' as remove_await;
@@ -89,6 +101,7 @@
 import 'replace_boolean_with_bool_test.dart' as replace_boolean_with_bool;
 import 'replace_colon_with_equals_test.dart' as replace_colon_with_equals;
 import 'replace_final_with_const_test.dart' as replace_final_with_const;
+import 'replace_new_with_const_test.dart' as replace_new_with_const;
 import 'replace_null_with_closure_test.dart' as replace_null_with_closure;
 import 'replace_return_type_future_test.dart' as replace_return_type_future;
 import 'replace_var_with_dynamic_test.dart' as replace_var_with_dynamic;
@@ -113,6 +126,8 @@
   defineReflectiveSuite(() {
     add_async.main();
     add_await.main();
+    add_const.main();
+    add_curly_braces.main();
     add_explicit_cast.main();
     add_field_formal_parameters.main();
     add_missing_enum_case_clauses.main();
@@ -125,15 +140,22 @@
     add_required.main();
     add_static.main();
     add_super_constructor_invocation.main();
+    add_type_annotation.main();
     analysis_options.main();
     change_argument_name.main();
     change_to.main();
     change_to_nearest_precise_value.main();
     change_to_static_access.main();
     change_type_annotation.main();
+    convert_documentation_into_line.main();
     convert_flutter_child.main();
     convert_flutter_children.main();
+    convert_into_expression_body.main();
+    convert_to_for_element.main();
+    convert_to_if_element.main();
+    convert_to_int_literal.main();
     convert_to_named_arguments.main();
+    convert_to_null_aware.main();
     create_class.main();
     create_constructor_for_final_field.main();
     create_constructor_super.main();
@@ -147,6 +169,7 @@
     create_missing_overrides.main();
     create_mixin.main();
     create_no_such_method.main();
+    create_setter.main();
     extend_class_for_mixin.main();
     fix.main();
     import_async.main();
@@ -158,6 +181,7 @@
     make_class_abstract.main();
     make_field_not_final.main();
     make_final.main();
+    make_variable_not_final.main();
     move_type_arguments_to_class.main();
     remove_annotation.main();
     remove_await.main();
@@ -186,6 +210,7 @@
     replace_boolean_with_bool.main();
     replace_colon_with_equals.main();
     replace_final_with_const.main();
+    replace_new_with_const.main();
     replace_null_with_closure.main();
     replace_return_type_future.main();
     replace_var_with_dynamic.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
index ab2da21..1d3a8ca 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
index 5a49867..6ad46df 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
@@ -3,7 +3,7 @@
 // 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/correction/fix_internal.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';
 
diff --git a/pkg/analysis_server/test/src/utilities/flutter_test.dart b/pkg/analysis_server/test/src/utilities/flutter_test.dart
index cad467a..76ce8fe 100644
--- a/pkg/analysis_server/test/src/utilities/flutter_test.dart
+++ b/pkg/analysis_server/test/src/utilities/flutter_test.dart
@@ -331,6 +331,44 @@
     expect(flutter.identifyWidgetExpression(expression), expression);
   }
 
+  test_identifyWidgetExpression_parent_forElement() async {
+    await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+main(bool b) {
+  [
+    for (var v in [0, 1, 2]) Container()
+  ];
+}
+
+void useWidget(Widget w) {}
+''');
+    var expression = findNode.instanceCreation('Container()');
+    expect(flutter.identifyWidgetExpression(expression), expression);
+  }
+
+  test_identifyWidgetExpression_parent_ifElement() async {
+    await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+main(bool b) {
+  [
+    if (b)
+      Text('then')
+    else
+      Text('else')
+  ];
+}
+
+void useWidget(Widget w) {}
+''');
+    var thenExpression = findNode.instanceCreation("Text('then')");
+    expect(flutter.identifyWidgetExpression(thenExpression), thenExpression);
+
+    var elseExpression = findNode.instanceCreation("Text('else')");
+    expect(flutter.identifyWidgetExpression(elseExpression), elseExpression);
+  }
+
   test_identifyWidgetExpression_parent_listLiteral() async {
     await resolveTestUnit('''
 import 'package:flutter/widgets.dart';
diff --git a/pkg/analysis_server/test/src/utilities/mock_packages.dart b/pkg/analysis_server/test/src/utilities/mock_packages.dart
index 929127f..81647c3 100644
--- a/pkg/analysis_server/test/src/utilities/mock_packages.dart
+++ b/pkg/analysis_server/test/src/utilities/mock_packages.dart
@@ -5,7 +5,8 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
+
+import '../../utils/package_root.dart' as package_root;
 
 /// Helper for copying files from "tests/mock_packages" to memory file system.
 class MockPackages {
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analysis_server/test/utils/package_root.dart
similarity index 100%
copy from pkg/front_end/lib/src/testing/package_root.dart
copy to pkg/analysis_server/test/utils/package_root.dart
diff --git a/pkg/analysis_server/test/verify_tests_test.dart b/pkg/analysis_server/test/verify_tests_test.dart
index e11636e..69bd9ac 100644
--- a/pkg/analysis_server/test/verify_tests_test.dart
+++ b/pkg/analysis_server/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
+import 'utils/package_root.dart' as package_root;
+
 main() {
   PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
   String packageRoot = provider.pathContext.normalize(package_root.packageRoot);
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java
new file mode 100644
index 0000000..c590fe5
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ *
+ * This file has been automatically generated. Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import com.google.common.collect.Lists;
+import com.google.dart.server.utilities.general.JsonUtilities;
+import com.google.dart.server.utilities.general.ObjectUtilities;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * A log entry from the server.
+ *
+ * @coverage dart.server.generated.types
+ */
+@SuppressWarnings("unused")
+public class ServerLogEntry {
+
+  public static final ServerLogEntry[] EMPTY_ARRAY = new ServerLogEntry[0];
+
+  public static final List<ServerLogEntry> EMPTY_LIST = Lists.newArrayList();
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log entry.
+   */
+  private final int time;
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data" field.
+   */
+  private final String kind;
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind" field.
+   */
+  private final String data;
+
+  /**
+   * Constructor for {@link ServerLogEntry}.
+   */
+  public ServerLogEntry(int time, String kind, String data) {
+    this.time = time;
+    this.kind = kind;
+    this.data = data;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof ServerLogEntry) {
+      ServerLogEntry other = (ServerLogEntry) obj;
+      return
+        other.time == time &&
+        ObjectUtilities.equals(other.kind, kind) &&
+        ObjectUtilities.equals(other.data, data);
+    }
+    return false;
+  }
+
+  public static ServerLogEntry fromJson(JsonObject jsonObject) {
+    int time = jsonObject.get("time").getAsInt();
+    String kind = jsonObject.get("kind").getAsString();
+    String data = jsonObject.get("data").getAsString();
+    return new ServerLogEntry(time, kind, data);
+  }
+
+  public static List<ServerLogEntry> fromJsonArray(JsonArray jsonArray) {
+    if (jsonArray == null) {
+      return EMPTY_LIST;
+    }
+    ArrayList<ServerLogEntry> list = new ArrayList<ServerLogEntry>(jsonArray.size());
+    Iterator<JsonElement> iterator = jsonArray.iterator();
+    while (iterator.hasNext()) {
+      list.add(fromJson(iterator.next().getAsJsonObject()));
+    }
+    return list;
+  }
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind" field.
+   */
+  public String getData() {
+    return data;
+  }
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data" field.
+   */
+  public String getKind() {
+    return kind;
+  }
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log entry.
+   */
+  public int getTime() {
+    return time;
+  }
+
+  @Override
+  public int hashCode() {
+    HashCodeBuilder builder = new HashCodeBuilder();
+    builder.append(time);
+    builder.append(kind);
+    builder.append(data);
+    return builder.toHashCode();
+  }
+
+  public JsonObject toJson() {
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.addProperty("time", time);
+    jsonObject.addProperty("kind", kind);
+    jsonObject.addProperty("data", data);
+    return jsonObject;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder builder = new StringBuilder();
+    builder.append("[");
+    builder.append("time=");
+    builder.append(time + ", ");
+    builder.append("kind=");
+    builder.append(kind + ", ");
+    builder.append("data=");
+    builder.append(data);
+    builder.append("]");
+    return builder.toString();
+  }
+
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java
new file mode 100644
index 0000000..9964b6f
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ *
+ * This file has been automatically generated. Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+/**
+ * An enumeration of the kinds of server long entries.
+ *
+ * @coverage dart.server.generated.types
+ */
+public class ServerLogEntryKind {
+
+  /**
+   * A notification from the server, such as "analysis.highlights". The "data" field contains a JSON
+   * object with abbreviated notification.
+   */
+  public static final String NOTIFICATION = "NOTIFICATION";
+
+  /**
+   * Arbitrary string, describing some event that happened in the server, e.g. starting a file
+   * analysis, and details which files were accessed. These entries are not structured, but provide
+   * context information about requests and notification, and can be related by "time" for further
+   * manual analysis.
+   */
+  public static final String RAW = "RAW";
+
+  /**
+   * A request from the client, as the server views it, e.g. "edit.getAssists". The "data" field
+   * contains a JSON object with abbreviated request.
+   */
+  public static final String REQUEST = "REQUEST";
+
+  /**
+   * Various counters and measurements related to execution of a request. The "data" field contains a
+   * JSON object with following fields:
+   *
+   * - "id" - the id of the request - copied from the request.
+   * - "method" - the method of the request, e.g. "edit.getAssists".
+   * - "clientRequestTime" - the time (milliseconds since epoch) at which the client made the request
+   *   - copied from the request.
+   * - "serverRequestTime" - the time (milliseconds since epoch) at which the server received and
+   *   decoded the JSON request.
+   * - "responseTime" - the time (milliseconds since epoch) at which the server created the response
+   *   to be encoded into JSON and sent to the client.
+   */
+  public static final String RESPONSE = "RESPONSE";
+
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
index fed7a98..99f51b9 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
@@ -15,6 +15,8 @@
  */
 public class ServerService {
 
+  public static final String LOG = "LOG";
+
   public static final String STATUS = "STATUS";
 
 }
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java b/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
index b9cc17e..71b5f70 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
@@ -54,12 +54,18 @@
   private final List<String> validElementKinds;
 
   /**
+   * The offset of the first character of the token in the file which it originated from.
+   */
+  private final int offset;
+
+  /**
    * Constructor for {@link TokenDetails}.
    */
-  public TokenDetails(String lexeme, String type, List<String> validElementKinds) {
+  public TokenDetails(String lexeme, String type, List<String> validElementKinds, int offset) {
     this.lexeme = lexeme;
     this.type = type;
     this.validElementKinds = validElementKinds;
+    this.offset = offset;
   }
 
   @Override
@@ -69,7 +75,8 @@
       return
         ObjectUtilities.equals(other.lexeme, lexeme) &&
         ObjectUtilities.equals(other.type, type) &&
-        ObjectUtilities.equals(other.validElementKinds, validElementKinds);
+        ObjectUtilities.equals(other.validElementKinds, validElementKinds) &&
+        other.offset == offset;
     }
     return false;
   }
@@ -78,7 +85,8 @@
     String lexeme = jsonObject.get("lexeme").getAsString();
     String type = jsonObject.get("type") == null ? null : jsonObject.get("type").getAsString();
     List<String> validElementKinds = jsonObject.get("validElementKinds") == null ? null : JsonUtilities.decodeStringList(jsonObject.get("validElementKinds").getAsJsonArray());
-    return new TokenDetails(lexeme, type, validElementKinds);
+    int offset = jsonObject.get("offset").getAsInt();
+    return new TokenDetails(lexeme, type, validElementKinds, offset);
   }
 
   public static List<TokenDetails> fromJsonArray(JsonArray jsonArray) {
@@ -101,6 +109,13 @@
   }
 
   /**
+   * The offset of the first character of the token in the file which it originated from.
+   */
+  public int getOffset() {
+    return offset;
+  }
+
+  /**
    * A unique id for the type of the identifier. Omitted if the token is not an identifier in a
    * reference position.
    */
@@ -123,6 +138,7 @@
     builder.append(lexeme);
     builder.append(type);
     builder.append(validElementKinds);
+    builder.append(offset);
     return builder.toHashCode();
   }
 
@@ -139,6 +155,7 @@
       }
       jsonObject.add("validElementKinds", jsonArrayValidElementKinds);
     }
+    jsonObject.addProperty("offset", offset);
     return jsonObject;
   }
 
@@ -151,7 +168,9 @@
     builder.append("type=");
     builder.append(type + ", ");
     builder.append("validElementKinds=");
-    builder.append(StringUtils.join(validElementKinds, ", "));
+    builder.append(StringUtils.join(validElementKinds, ", ") + ", ");
+    builder.append("offset=");
+    builder.append(offset);
     builder.append("]");
     return builder.toString();
   }
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 3a635e1..712bdc4 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  <version>1.27.2</version>
+  <version>1.27.3</version>
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -311,6 +311,16 @@
       </field>
     </params>
   </notification>
+  <notification event="log" experimental="true">
+    <p>
+      The stream of entries describing events happened in the server.
+    </p>
+    <params>
+      <field name="entry">
+        <ref>ServerLogEntry</ref>
+      </field>
+    </params>
+  </notification>
   <notification event="status">
     <p>
       Reports the current status of the server. Parameters are
@@ -4096,6 +4106,13 @@
           Omitted if the token is not an identifier.
         </p>
       </field>
+      <field name="offset">
+        <ref>int</ref>
+        <p>
+          The offset of the first character of the token in the file which it
+          originated from.
+        </p>
+      </field>
     </object>
   </type>
   <type name="ExecutionService">
@@ -5234,6 +5251,7 @@
       An enumeration of the services provided by the server domain.
     </p>
     <enum>
+      <value><code>LOG</code></value>
       <value><code>STATUS</code></value>
     </enum>
   </type>
@@ -5308,6 +5326,94 @@
       </field>
     </object>
   </type>
+  <type name="ServerLogEntry" experimental="true">
+    <p>
+      A log entry from the server.
+    </p>
+    <object>
+      <field name="time">
+        <ref>int</ref>
+        <p>
+          The time (milliseconds since epoch) at which the server created
+          this log entry.
+        </p>
+      </field>
+      <field name="kind" >
+        <ref>ServerLogEntryKind</ref>
+        <p>
+          The kind of the entry, used to determine how to interpret the "data"
+          field.
+        </p>
+      </field>
+      <field name="data">
+        <ref>String</ref>
+        <p>
+          The payload of the entry, the actual format is determined by the
+          "kind" field.
+        </p>
+      </field>
+    </object>
+  </type>
+  <type name="ServerLogEntryKind" experimental="true">
+    <p>
+      An enumeration of the kinds of server long entries.
+    </p>
+    <enum>
+      <value>
+        <code>NOTIFICATION</code>
+        <p>
+          A notification from the server, such as "analysis.highlights".
+          The "data" field contains a JSON object with abbreviated notification.
+        </p>
+      </value>
+      <value>
+        <code>RAW</code>
+        <p>
+          Arbitrary string, describing some event that happened in the server,
+          e.g. starting a file analysis, and details which files were accessed.
+          These entries are not structured, but provide context information
+          about requests and notification, and can be related by "time" for
+          further manual analysis.
+        </p>
+      </value>
+      <value>
+        <code>REQUEST</code>
+        <p>
+          A request from the client, as the server views it, e.g.
+          "edit.getAssists". The "data" field contains a JSON object with
+          abbreviated request.
+        </p>
+      </value>
+      <value>
+        <code>RESPONSE</code>
+        <p>
+          Various counters and measurements related to execution of a request.
+          The "data" field contains a JSON object with following fields:
+        </p>
+        <ul>
+          <li>
+            "id" - the id of the request - copied from the request.
+          </li>
+          <li>
+            "method" - the method of the request, e.g. "edit.getAssists".
+          </li>
+          <li>
+            "clientRequestTime" - the time (milliseconds since epoch) at which
+            the client made the request - copied from the request.
+          </li>
+          <li>
+            "serverRequestTime" - the time (milliseconds since epoch) at which
+            the server received and decoded the JSON request.
+          </li>
+          <li>
+            "responseTime" - the time (milliseconds since epoch) at which the
+            server created the response to be encoded into JSON and sent to the
+            client.
+          </li>
+        </ul>
+      </value>
+    </enum>
+  </type>
 </types>
 <refactorings>
   <h2><a name="refactorings">Refactorings</a></h2>
diff --git a/pkg/analysis_server_client/lib/handler/notification_handler.dart b/pkg/analysis_server_client/lib/handler/notification_handler.dart
index b85aa31..cd9b88f 100644
--- a/pkg/analysis_server_client/lib/handler/notification_handler.dart
+++ b/pkg/analysis_server_client/lib/handler/notification_handler.dart
@@ -101,6 +101,9 @@
         onServerError(
             new ServerErrorParams.fromJson(decoder, 'params', params));
         break;
+      case SERVER_NOTIFICATION_LOG:
+        onServerLog(new ServerLogParams.fromJson(decoder, 'params', params));
+        break;
       case SERVER_NOTIFICATION_STATUS:
         onServerStatus(
             new ServerStatusParams.fromJson(decoder, 'params', params));
@@ -279,6 +282,9 @@
   /// notification.
   void onServerError(ServerErrorParams params) {}
 
+  /// The stream of entries describing events happened in the server.
+  void onServerLog(ServerLogParams params) {}
+
   /// Reports the current status of the server. Parameters are
   /// omitted if there has been no change in the status
   /// represented by that parameter.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index f51b81c..686011c 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.27.2';
+const String PROTOCOL_VERSION = '1.27.3';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -341,6 +341,8 @@
 const String SERVER_NOTIFICATION_ERROR_IS_FATAL = 'isFatal';
 const String SERVER_NOTIFICATION_ERROR_MESSAGE = 'message';
 const String SERVER_NOTIFICATION_ERROR_STACK_TRACE = 'stackTrace';
+const String SERVER_NOTIFICATION_LOG = 'server.log';
+const String SERVER_NOTIFICATION_LOG_ENTRY = 'entry';
 const String SERVER_NOTIFICATION_STATUS = 'server.status';
 const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
 const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 80ae759..d0c24a3 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -22728,21 +22728,330 @@
 }
 
 /**
+ * ServerLogEntry
+ *
+ * {
+ *   "time": int
+ *   "kind": ServerLogEntryKind
+ *   "data": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntry implements HasToJson {
+  int _time;
+
+  ServerLogEntryKind _kind;
+
+  String _data;
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log
+   * entry.
+   */
+  int get time => _time;
+
+  /**
+   * The time (milliseconds since epoch) at which the server created this log
+   * entry.
+   */
+  void set time(int value) {
+    assert(value != null);
+    this._time = value;
+  }
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data"
+   * field.
+   */
+  ServerLogEntryKind get kind => _kind;
+
+  /**
+   * The kind of the entry, used to determine how to interpret the "data"
+   * field.
+   */
+  void set kind(ServerLogEntryKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind"
+   * field.
+   */
+  String get data => _data;
+
+  /**
+   * The payload of the entry, the actual format is determined by the "kind"
+   * field.
+   */
+  void set data(String value) {
+    assert(value != null);
+    this._data = value;
+  }
+
+  ServerLogEntry(int time, ServerLogEntryKind kind, String data) {
+    this.time = time;
+    this.kind = kind;
+    this.data = data;
+  }
+
+  factory ServerLogEntry.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int time;
+      if (json.containsKey("time")) {
+        time = jsonDecoder.decodeInt(jsonPath + ".time", json["time"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "time");
+      }
+      ServerLogEntryKind kind;
+      if (json.containsKey("kind")) {
+        kind = new ServerLogEntryKind.fromJson(
+            jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "kind");
+      }
+      String data;
+      if (json.containsKey("data")) {
+        data = jsonDecoder.decodeString(jsonPath + ".data", json["data"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "data");
+      }
+      return new ServerLogEntry(time, kind, data);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "ServerLogEntry", json);
+    }
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["time"] = time;
+    result["kind"] = kind.toJson();
+    result["data"] = data;
+    return result;
+  }
+
+  @override
+  String toString() => json.encode(toJson());
+
+  @override
+  bool operator ==(other) {
+    if (other is ServerLogEntry) {
+      return time == other.time && kind == other.kind && data == other.data;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, time.hashCode);
+    hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = JenkinsSmiHash.combine(hash, data.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ *   NOTIFICATION
+ *   RAW
+ *   REQUEST
+ *   RESPONSE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntryKind implements Enum {
+  /**
+   * A notification from the server, such as "analysis.highlights". The "data"
+   * field contains a JSON object with abbreviated notification.
+   */
+  static const ServerLogEntryKind NOTIFICATION =
+      const ServerLogEntryKind._("NOTIFICATION");
+
+  /**
+   * Arbitrary string, describing some event that happened in the server, e.g.
+   * starting a file analysis, and details which files were accessed. These
+   * entries are not structured, but provide context information about requests
+   * and notification, and can be related by "time" for further manual
+   * analysis.
+   */
+  static const ServerLogEntryKind RAW = const ServerLogEntryKind._("RAW");
+
+  /**
+   * A request from the client, as the server views it, e.g. "edit.getAssists".
+   * The "data" field contains a JSON object with abbreviated request.
+   */
+  static const ServerLogEntryKind REQUEST =
+      const ServerLogEntryKind._("REQUEST");
+
+  /**
+   * Various counters and measurements related to execution of a request. The
+   * "data" field contains a JSON object with following fields:
+   *
+   * - "id" - the id of the request - copied from the request.
+   * - "method" - the method of the request, e.g. "edit.getAssists".
+   * - "clientRequestTime" - the time (milliseconds since epoch) at which the
+   *   client made the request - copied from the request.
+   * - "serverRequestTime" - the time (milliseconds since epoch) at which the
+   *   server received and decoded the JSON request.
+   * - "responseTime" - the time (milliseconds since epoch) at which the server
+   *   created the response to be encoded into JSON and sent to the client.
+   */
+  static const ServerLogEntryKind RESPONSE =
+      const ServerLogEntryKind._("RESPONSE");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<ServerLogEntryKind> VALUES = const <ServerLogEntryKind>[
+    NOTIFICATION,
+    RAW,
+    REQUEST,
+    RESPONSE
+  ];
+
+  @override
+  final String name;
+
+  const ServerLogEntryKind._(this.name);
+
+  factory ServerLogEntryKind(String name) {
+    switch (name) {
+      case "NOTIFICATION":
+        return NOTIFICATION;
+      case "RAW":
+        return RAW;
+      case "REQUEST":
+        return REQUEST;
+      case "RESPONSE":
+        return RESPONSE;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory ServerLogEntryKind.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new ServerLogEntryKind(json);
+      } catch (_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "ServerLogEntryKind", json);
+  }
+
+  @override
+  String toString() => "ServerLogEntryKind.$name";
+
+  String toJson() => name;
+}
+
+/**
+ * server.log params
+ *
+ * {
+ *   "entry": ServerLogEntry
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogParams implements HasToJson {
+  ServerLogEntry _entry;
+
+  ServerLogEntry get entry => _entry;
+
+  void set entry(ServerLogEntry value) {
+    assert(value != null);
+    this._entry = value;
+  }
+
+  ServerLogParams(ServerLogEntry entry) {
+    this.entry = entry;
+  }
+
+  factory ServerLogParams.fromJson(
+      JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      ServerLogEntry entry;
+      if (json.containsKey("entry")) {
+        entry = new ServerLogEntry.fromJson(
+            jsonDecoder, jsonPath + ".entry", json["entry"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "entry");
+      }
+      return new ServerLogParams(entry);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "server.log params", json);
+    }
+  }
+
+  factory ServerLogParams.fromNotification(Notification notification) {
+    return new ServerLogParams.fromJson(
+        new ResponseDecoder(null), "params", notification.params);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["entry"] = entry.toJson();
+    return result;
+  }
+
+  Notification toNotification() {
+    return new Notification("server.log", toJson());
+  }
+
+  @override
+  String toString() => json.encode(toJson());
+
+  @override
+  bool operator ==(other) {
+    if (other is ServerLogParams) {
+      return entry == other.entry;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, entry.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
+
+/**
  * ServerService
  *
  * enum {
+ *   LOG
  *   STATUS
  * }
  *
  * Clients may not extend, implement or mix-in this class.
  */
 class ServerService implements Enum {
+  static const ServerService LOG = const ServerService._("LOG");
+
   static const ServerService STATUS = const ServerService._("STATUS");
 
   /**
    * A list containing all of the enum values that are defined.
    */
-  static const List<ServerService> VALUES = const <ServerService>[STATUS];
+  static const List<ServerService> VALUES = const <ServerService>[LOG, STATUS];
 
   @override
   final String name;
@@ -22751,6 +23060,8 @@
 
   factory ServerService(String name) {
     switch (name) {
+      case "LOG":
+        return LOG;
       case "STATUS":
         return STATUS;
     }
@@ -23071,6 +23382,7 @@
  *   "lexeme": String
  *   "type": optional String
  *   "validElementKinds": optional List<String>
+ *   "offset": int
  * }
  *
  * Clients may not extend, implement or mix-in this class.
@@ -23082,6 +23394,8 @@
 
   List<String> _validElementKinds;
 
+  int _offset;
+
   /**
    * The token's lexeme.
    */
@@ -23127,10 +23441,27 @@
     this._validElementKinds = value;
   }
 
-  TokenDetails(String lexeme, {String type, List<String> validElementKinds}) {
+  /**
+   * The offset of the first character of the token in the file which it
+   * originated from.
+   */
+  int get offset => _offset;
+
+  /**
+   * The offset of the first character of the token in the file which it
+   * originated from.
+   */
+  void set offset(int value) {
+    assert(value != null);
+    this._offset = value;
+  }
+
+  TokenDetails(String lexeme, int offset,
+      {String type, List<String> validElementKinds}) {
     this.lexeme = lexeme;
     this.type = type;
     this.validElementKinds = validElementKinds;
+    this.offset = offset;
   }
 
   factory TokenDetails.fromJson(
@@ -23156,7 +23487,13 @@
             json["validElementKinds"],
             jsonDecoder.decodeString);
       }
-      return new TokenDetails(lexeme,
+      int offset;
+      if (json.containsKey("offset")) {
+        offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+      } else {
+        throw jsonDecoder.mismatch(jsonPath, "offset");
+      }
+      return new TokenDetails(lexeme, offset,
           type: type, validElementKinds: validElementKinds);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "TokenDetails", json);
@@ -23173,6 +23510,7 @@
     if (validElementKinds != null) {
       result["validElementKinds"] = validElementKinds;
     }
+    result["offset"] = offset;
     return result;
   }
 
@@ -23185,7 +23523,8 @@
       return lexeme == other.lexeme &&
           type == other.type &&
           listEqual(validElementKinds, other.validElementKinds,
-              (String a, String b) => a == b);
+              (String a, String b) => a == b) &&
+          offset == other.offset;
     }
     return false;
   }
@@ -23196,6 +23535,7 @@
     hash = JenkinsSmiHash.combine(hash, lexeme.hashCode);
     hash = JenkinsSmiHash.combine(hash, type.hashCode);
     hash = JenkinsSmiHash.combine(hash, validElementKinds.hashCode);
+    hash = JenkinsSmiHash.combine(hash, offset.hashCode);
     return JenkinsSmiHash.finish(hash);
   }
 }
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 29ba4a7..6c308d7 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,8 +1,15 @@
-## 0.38.2-dev
+## 0.38.2
 * The type of `FunctionTypeAlias.declaredElement` has been refined to
   `FunctionTypeAliasElement`.  Since the new type is a refinement of
   the old one, the only effect on clients should be to make certain
   casts unnecessary.
+* Deprecated `HintCode.INVALID_REQUIRED_PARAM` and replaced it with more
+  specific hints, `HintCode.INVALID_REQUIRED_NAMED_PARAM`,
+  `HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM`, and
+  `HintCode.INVALID_REQUIRED_POSITIONAL_PARAM` to address #36966.
+* Deprecated `CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS`.  It
+  has been renamed to
+  `CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS`.
 
 ## 0.38.1
 * LinterVistor support for extension method AST nodes.
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 79c25fc..1b18be9 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -4787,6 +4787,9 @@
 
   /// The spread operator, either '...' or '...?'.
   Token get spreadOperator;
+
+  /// Whether this is a null-aware spread, as opposed to a non-null spread.
+  bool get isNullAware;
 }
 
 /// A node that represents a statement.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index da6c473..0eda2b3 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1389,14 +1389,7 @@
 /// A local variable.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class LocalVariableElement implements LocalElement, VariableElement {
-  /// Return `true` if this local variable uses late evaluation semantics.
-  ///
-  /// This will always return `false` unless the experiment 'non-nullable' is
-  /// enabled.
-  @experimental
-  bool get isLate;
-}
+abstract class LocalVariableElement implements LocalElement, VariableElement {}
 
 /// An element that represents a method defined within a class.
 ///
@@ -1602,13 +1595,6 @@
   /// will be synthetic.
   PropertyAccessorElement get getter;
 
-  /// Return `true` if this variable uses late evaluation semantics.
-  ///
-  /// This will always return `false` unless the experiment 'non-nullable' is
-  /// enabled.
-  @experimental
-  bool get isLate;
-
   /// Return the propagated type of this variable, or `null` if type propagation
   /// has not been performed, for example because the variable is not final.
   @deprecated
@@ -1745,6 +1731,13 @@
   /// even though they are implicitly final.
   bool get isFinal;
 
+  /// Return `true` if this variable uses late evaluation semantics.
+  ///
+  /// This will always return `false` unless the experiment 'non-nullable' is
+  /// enabled.
+  @experimental
+  bool get isLate;
+
   /// Return `true` if this variable is potentially mutated somewhere in a
   /// closure. This information is only available for local variables (including
   /// parameters) and only after the compilation unit containing the variable
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index fde3636..94175cc 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -73,6 +73,7 @@
   CompileTimeErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS,
   CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT,
   CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT,
+  CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME,
   CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_PREFIX_NAME,
   CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
   CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME,
@@ -136,10 +137,8 @@
   CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
   CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
   CompileTimeErrorCode.EXTENDS_NON_CLASS,
+  CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
   CompileTimeErrorCode.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE,
-  CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER,
-  CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
-  CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
   CompileTimeErrorCode.EXTENSION_DECLARES_MEMBER_OF_OBJECT,
   CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
   CompileTimeErrorCode.EXTENSION_OVERRIDE_ARGUMENT_NOT_ASSIGNABLE,
@@ -246,6 +245,8 @@
   CompileTimeErrorCode.NON_SYNC_FACTORY,
   CompileTimeErrorCode.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
   CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS,
+  // ignore: deprecated_member_use_from_same_package
+  CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
   CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD,
   CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR,
   CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_VARIABLE,
@@ -337,7 +338,11 @@
   HintCode.INVALID_FACTORY_METHOD_IMPL,
   HintCode.INVALID_IMMUTABLE_ANNOTATION,
   HintCode.INVALID_LITERAL_ANNOTATION,
+  HintCode.INVALID_REQUIRED_NAMED_PARAM,
+  HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+  // ignore: deprecated_member_use_from_same_package
   HintCode.INVALID_REQUIRED_PARAM,
+  HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
   HintCode.INVALID_SEALED_ANNOTATION,
   HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
   HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
@@ -458,6 +463,9 @@
   ParserErrorCode.EXPECTED_TYPE_NAME,
   ParserErrorCode.EXPERIMENT_NOT_ENABLED,
   ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
+  ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER,
+  ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
+  ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
   ParserErrorCode.EXTERNAL_AFTER_CONST,
   ParserErrorCode.EXTERNAL_AFTER_FACTORY,
   ParserErrorCode.EXTERNAL_AFTER_STATIC,
@@ -537,6 +545,7 @@
   ParserErrorCode.MISSING_TYPEDEF_PARAMETERS,
   ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH,
   ParserErrorCode.MIXED_PARAMETER_GROUPS,
+  ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR,
   ParserErrorCode.MODIFIER_OUT_OF_ORDER,
   ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
   ParserErrorCode.MULTIPLE_ON_CLAUSES,
@@ -657,7 +666,9 @@
   StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER,
   StaticWarningCode.CONST_WITH_ABSTRACT_CLASS,
   StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_NAMED,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED,
   StaticWarningCode.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION,
   StaticWarningCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
@@ -668,6 +679,7 @@
   StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
   StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS,
   StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_NAMED,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.IMPORT_OF_NON_LIBRARY,
   StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
   StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
@@ -691,11 +703,14 @@
   StaticWarningCode.NON_VOID_RETURN_FOR_OPERATOR,
   StaticWarningCode.NON_VOID_RETURN_FOR_SETTER,
   StaticWarningCode.NOT_A_TYPE,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
   StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
   StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE,
   StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.REDIRECT_TO_NON_CLASS,
   StaticWarningCode.RETURN_WITHOUT_VALUE,
   StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE,
@@ -706,10 +721,12 @@
   StaticWarningCode.TYPE_TEST_WITH_NON_TYPE,
   StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
   StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.UNDEFINED_CLASS,
   StaticWarningCode.UNDEFINED_CLASS_BOOLEAN,
   StaticWarningCode.UNDEFINED_IDENTIFIER,
   StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT,
+  // ignore: deprecated_member_use_from_same_package
   StaticWarningCode.UNDEFINED_NAMED_PARAMETER,
   StaticWarningCode.UNNECESSARY_NON_NULL_ASSERTION,
   StaticWarningCode.UNNECESSARY_NULL_AWARE_CALL,
diff --git a/pkg/analyzer/lib/instrumentation/instrumentation.dart b/pkg/analyzer/lib/instrumentation/instrumentation.dart
index bcf859c..63920eb 100644
--- a/pkg/analyzer/lib/instrumentation/instrumentation.dart
+++ b/pkg/analyzer/lib/instrumentation/instrumentation.dart
@@ -5,8 +5,6 @@
 import 'dart:async';
 import 'dart:convert';
 
-import 'package:analyzer/src/task/api/model.dart';
-
 /**
  * A container with analysis performance constants.
  */
@@ -123,17 +121,6 @@
   String get _timestamp => new DateTime.now().millisecondsSinceEpoch.toString();
 
   /**
-   * Log that the given analysis [task] is being performed in the given
-   * [context].
-   */
-  void logAnalysisTask(String context, AnalysisTask task) {
-    if (_instrumentationServer != null) {
-      _instrumentationServer
-          .log(_join([TAG_ANALYSIS_TASK, context, task.description]));
-    }
-  }
-
-  /**
    * Log the fact that an error, described by the given [message], has occurred.
    */
   void logError(String message) {
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index 65349a0..e0b4d6a 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -2,1544 +2,17 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:async';
-import 'dart:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_collection.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/model.dart';
 
-/**
- * The cache results visiting function type.
- */
-typedef void CacheResultVisitor(AnalysisTarget target, ResultData data);
-
-/**
- * Return `true` if the [result] of the [target] should be flushed.
- */
-typedef bool FlushResultFilter<V>(
-    AnalysisTarget target, ResultDescriptor<V> result);
-
-/**
- * Return `true` if the given [target] is a priority one.
- */
-typedef bool IsPriorityAnalysisTarget(AnalysisTarget target);
-
-/**
- * An LRU cache of results produced by analysis.
- */
 class AnalysisCache {
-  /**
-   * A flag used to control whether trace information should be produced when
-   * the content of the cache is modified.
-   */
-  static bool _TRACE_CHANGES = false;
-
-  /**
-   * An array containing the partitions of which this cache is comprised.
-   */
-  final List<CachePartition> _partitions;
-
-  /**
-   * The [StreamController] reporting [InvalidatedResult]s.
-   */
-  final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
-      new ReentrantSynchronousStream<InvalidatedResult>();
-
-  final List<ReentrantSynchronousStreamSubscription>
-      onResultInvalidatedPartitionSubscriptions =
-      <ReentrantSynchronousStreamSubscription>[];
-
-  /**
-   * Initialize a newly created cache to have the given [_partitions]. The
-   * partitions will be searched in the order in which they appear in the array,
-   * so the most specific partition (usually an [SdkCachePartition]) should be
-   * first and the most general (usually a [UniversalCachePartition]) last.
-   */
-  AnalysisCache(this._partitions) {
-    for (CachePartition partition in _partitions) {
-      partition.containingCaches.add(this);
-      ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription =
-          partition.onResultInvalidated.listen((InvalidatedResult event) {
-        onResultInvalidated.add(event);
-      });
-      onResultInvalidatedPartitionSubscriptions.add(subscription);
-    }
-  }
-
-  /**
-   * Return an iterator returning all of the [Source] targets.
-   */
-  Iterable<Source> get sources {
-    return _partitions
-        .map((CachePartition partition) => partition.sources)
-        .expand((Iterable<Source> sources) => sources);
-  }
-
-  // TODO(brianwilkerson) Implement or delete this.
-//  /**
-//   * Return information about each of the partitions in this cache.
-//   */
-//  List<AnalysisContextStatistics_PartitionData> get partitionData {
-//    int count = _partitions.length;
-//    List<AnalysisContextStatistics_PartitionData> data =
-//        new List<AnalysisContextStatistics_PartitionData>(count);
-//    for (int i = 0; i < count; i++) {
-//      CachePartition partition = _partitions[i];
-//      data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl(
-//          partition.astSize,
-//          partition.map.length);
-//    }
-//    return data;
-//  }
-
-  /**
-   * Free any allocated resources and references.
-   */
-  void dispose() {
-    for (ReentrantSynchronousStreamSubscription subscription
-        in onResultInvalidatedPartitionSubscriptions) {
-      subscription.cancel();
-    }
-    for (CachePartition partition in _partitions) {
-      partition.containingCaches.remove(this);
-    }
-  }
-
-  /**
-   * Flush results that satisfy the given [filter].
-   */
-  void flush(FlushResultFilter filter) {
-    for (CachePartition partition in _partitions) {
-      partition.flush(filter);
-    }
-  }
-
-  /**
-   * Return the entry associated with the given [target].
-   */
-  CacheEntry get(AnalysisTarget target) {
-    int count = _partitions.length;
-    for (int i = 0; i < count; i++) {
-      CachePartition partition = _partitions[i];
-      if (partition.isResponsibleFor(target)) {
-        return partition.get(target);
-      }
-    }
-    //
-    // We should never get to this point because the last partition should
-    // always be a universal partition, except in the case of the SDK context,
-    // in which case the target should always be part of the SDK.
-    //
-    return null;
-  }
-
-  /**
-   * Return the context to which the given [target] was explicitly added.
-   */
-  InternalAnalysisContext getContextFor(AnalysisTarget target) {
-    int count = _partitions.length;
-    for (int i = 0; i < count; i++) {
-      CachePartition partition = _partitions[i];
-      if (partition.isResponsibleFor(target)) {
-        return partition.context;
-      }
-    }
-    //
-    // We should never get to this point because the last partition should
-    // always be a universal partition, except in the case of the SDK context,
-    // in which case the target should always be part of the SDK.
-    //
-    // TODO(brianwilkerson) Throw an exception here.
-    AnalysisEngine.instance.logger.logInformation(
-        'Could not find context for $target',
-        new CaughtException(new AnalysisException(), null));
-    return null;
-  }
-
-  /**
-   * Return [Source]s whose full path is equal to the given [path].
-   * Maybe empty, but not `null`.
-   */
-  List<Source> getSourcesWithFullName(String path) {
-    List<Source> sources = <Source>[];
-    for (CachePartition partition in _partitions) {
-      List<Source> partitionSources = partition.getSourcesWithFullName(path);
-      sources.addAll(partitionSources);
-    }
-    return sources;
-  }
-
-  /**
-   * Return the state of the given [result] for the given [target].
-   *
-   * It does not update the cache, if the corresponding [CacheEntry] does not
-   * exist, then [CacheState.INVALID] is returned.
-   */
-  CacheState getState(AnalysisTarget target, ResultDescriptor result) {
-    CacheEntry entry = get(target);
-    if (entry == null) {
-      return CacheState.INVALID;
-    }
-    return entry.getState(result);
-  }
-
-  /**
-   * Return the value of the given [result] for the given [target].
-   *
-   * It does not update the cache, if the corresponding [CacheEntry] does not
-   * exist, then the default value is returned.
-   */
-  V getValue<V>(AnalysisTarget target, ResultDescriptor<V> result) {
-    CacheEntry entry = get(target);
-    if (entry == null) {
-      return result.defaultValue;
-    }
-    return entry.getValue(result);
-  }
-
-  /**
-   * Return an iterator returning all of the map entries mapping targets to
-   * cache entries. If the [context] is not `null`, then only entries that are
-   * owned by the given context will be returned.
-   */
-  MapIterator<AnalysisTarget, CacheEntry> iterator(
-      {InternalAnalysisContext context: null}) {
-    List<Map<AnalysisTarget, CacheEntry>> maps =
-        <Map<AnalysisTarget, CacheEntry>>[];
-    for (CachePartition partition in _partitions) {
-      if (context == null || partition.context == context) {
-        maps.add(partition.entryMap);
-      }
-    }
-    return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
-  }
-
-  /**
-   * Puts the given [entry] into the cache.
-   */
-  void put(CacheEntry entry) {
-    AnalysisTarget target = entry.target;
-    entry.fixExceptionState();
-    int count = _partitions.length;
-    for (int i = 0; i < count; i++) {
-      CachePartition partition = _partitions[i];
-      if (partition.isResponsibleFor(target)) {
-        if (_TRACE_CHANGES) {
-          CacheEntry oldEntry = partition.get(target);
-          if (oldEntry == null) {
-            AnalysisEngine.instance.logger
-                .logInformation('Added a cache entry for $target.');
-          } else {
-            AnalysisEngine.instance.logger
-                .logInformation('Modified the cache entry for $target.');
-//                'Diff = ${entry.getDiff(oldEntry)}');
-          }
-        }
-        partition.put(entry);
-        return;
-      }
-    }
-    // TODO(brianwilkerson) Handle the case where no partition was found,
-    // possibly by throwing an exception.
-  }
-
-  /**
-   * Remove all information related to the given [target] from this cache.
-   * Return the entry associated with the target, or `null` if there was cache
-   * entry for the target.
-   */
-  CacheEntry remove(AnalysisTarget target) {
-    int count = _partitions.length;
-    for (int i = 0; i < count; i++) {
-      CachePartition partition = _partitions[i];
-      if (partition.isResponsibleFor(target)) {
-        if (_TRACE_CHANGES) {
-          AnalysisEngine.instance.logger
-              .logInformation('Removed the cache entry for $target.');
-        }
-        CacheEntry entry = partition.remove(target);
-        if (entry != null) {
-          entry.dispose();
-        }
-        return entry;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the number of targets that are mapped to cache entries.
-   */
-  int size() {
-    int size = 0;
-    int count = _partitions.length;
-    for (int i = 0; i < count; i++) {
-      size += _partitions[i].size();
-    }
-    return size;
-  }
+  AnalysisCache(List<CachePartition> partitions);
 }
 
-/**
- * The information cached by an analysis context about an individual target.
- */
-class CacheEntry {
-  /**
-   * The index of the flag indicating whether the source was explicitly added to
-   * the context or whether the source was implicitly added because it was
-   * referenced by another source.
-   */
-  static int _EXPLICITLY_ADDED_FLAG = 0;
-
-  /**
-   * The next visit process identifier.
-   */
-  static int nextVisitId = 0;
-
-  /**
-   * A table containing the number of times the value of a result descriptor was
-   * recomputed after having been flushed.
-   */
-  static final Map<ResultDescriptor, int> recomputedCounts =
-      new HashMap<ResultDescriptor, int>();
-
-  /**
-   * The target this entry is about.
-   */
-  final AnalysisTarget target;
-
-  /**
-   * The partition that is responsible for this entry.
-   */
-  CachePartition _partition;
-
-  /**
-   * The most recent time at which the state of the target matched the state
-   * represented by this entry, `-1` if the target does not exist.
-   */
-  int modificationTime = -1;
-
-  /**
-   * The exception that caused one or more values to have a state of
-   * [CacheState.ERROR].
-   */
-  CaughtException _exception;
-
-  /**
-   * A bit-encoding of boolean flags associated with this entry's target.
-   */
-  int _flags = 0;
-
-  /**
-   * A table mapping result descriptors to the cached values of those results.
-   */
-  Map<ResultDescriptor, ResultData> _resultMap =
-      new HashMap<ResultDescriptor, ResultData>();
-
-  CacheEntry(this.target);
-
-  /**
-   * The exception that caused one or more values to have a state of
-   * [CacheState.ERROR].
-   */
-  CaughtException get exception => _exception;
-
-  /**
-   * Return `true` if the source was explicitly added to the context or `false`
-   * if the source was implicitly added because it was referenced by another
-   * source.
-   */
-  bool get explicitlyAdded => _getFlag(_EXPLICITLY_ADDED_FLAG);
-
-  /**
-   * Set whether the source was explicitly added to the context to match the
-   * [explicitlyAdded] flag.
-   */
-  void set explicitlyAdded(bool explicitlyAdded) {
-    _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded);
-  }
-
-  /**
-   * Return a list of result descriptors for results whose state is not
-   * [CacheState.INVALID].
-   */
-  List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList();
-
-  /**
-   * Notifies the entry that the client is going to stop using it.
-   */
-  void dispose() {
-    _resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
-      TargetedResult result = new TargetedResult(target, descriptor);
-      for (TargetedResult dependedOnResult in data.dependedOnResults) {
-        for (AnalysisCache cache in _partition.containingCaches) {
-          CacheEntry entry = cache.get(dependedOnResult.target);
-          if (entry != null) {
-            ResultData data =
-                entry.getResultDataOrNull(dependedOnResult.result);
-            if (data != null) {
-              data.dependentResults.remove(result);
-            }
-          }
-        }
-      }
-    });
-    _resultMap.clear();
-  }
-
-  /**
-   * Fix the state of the [exception] to match the current state of the entry.
-   */
-  void fixExceptionState() {
-    if (!hasErrorState()) {
-      _exception = null;
-    }
-  }
-
-  /**
-   * Flush results that satisfy the given [filter].
-   */
-  void flush(FlushResultFilter filter) {
-    _resultMap.forEach((ResultDescriptor result, ResultData data) {
-      if (filter(target, result)) {
-        data.flush();
-      }
-    });
-  }
-
-  /**
-   * Return the result data associated with the [descriptor], creating one if it
-   * isn't there.
-   */
-  ResultData getResultData(ResultDescriptor descriptor) {
-    return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor));
-  }
-
-  /**
-   * Return the result data associated with the [descriptor], or `null` if there
-   * is no data currently associated with the descriptor.
-   */
-  ResultData getResultDataOrNull(ResultDescriptor descriptor) =>
-      _resultMap[descriptor];
-
-  /**
-   * Return the state of the result represented by the given [descriptor].
-   */
-  CacheState getState(ResultDescriptor descriptor) {
-    ResultData data = _resultMap[descriptor];
-    if (data == null) {
-      return CacheState.INVALID;
-    }
-    return data.state;
-  }
-
-  /**
-   * Return the value of the result represented by the given [descriptor], or
-   * the default value for the result if this entry does not have a valid value.
-   */
-  V getValue<V>(ResultDescriptor<V> descriptor) {
-    ResultData data = _resultMap[descriptor];
-    if (data == null) {
-      return descriptor.defaultValue;
-    }
-    if (_partition != null) {
-      _partition.resultAccessed(target, descriptor);
-    }
-    return data.value as V;
-  }
-
-  /**
-   * Return `true` if the state of any data value is [CacheState.ERROR].
-   */
-  bool hasErrorState() {
-    for (ResultData data in _resultMap.values) {
-      if (data.state == CacheState.ERROR) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Invalidate all of the information associated with this entry's target.
-   */
-  void invalidateAllInformation() {
-    _resultMap.clear();
-    _exception = null;
-  }
-
-  /**
-   * Return `true` if the state of the result represented by the given
-   * [descriptor] is [CacheState.INVALID].
-   */
-  bool isInvalid(ResultDescriptor descriptor) =>
-      getState(descriptor) == CacheState.INVALID;
-
-  /**
-   * Return `true` if the state of the result represented by the given
-   * [descriptor] is [CacheState.VALID].
-   */
-  bool isValid(ResultDescriptor descriptor) =>
-      getState(descriptor) == CacheState.VALID;
-
-  /**
-   * For each of the given [descriptors], set their states to
-   * [CacheState.ERROR], their values to the corresponding default values, and
-   * remember the [exception] that caused this state.
-   */
-  void setErrorState(
-      CaughtException exception, List<ResultDescriptor> descriptors) {
-    if (descriptors == null || descriptors.isEmpty) {
-      throw new ArgumentError('at least one descriptor is expected');
-    }
-    if (exception == null) {
-      throw new ArgumentError('an exception is expected');
-    }
-    this._exception = exception;
-    for (ResultDescriptor descriptor in descriptors) {
-      _setErrorState(descriptor, exception);
-    }
-  }
-
-  /**
-   * Set the state of the result represented by the given [descriptor] to the
-   * given [state].
-   */
-  void setState(ResultDescriptor descriptor, CacheState state, {Delta delta}) {
-    if (state == CacheState.ERROR) {
-      throw new ArgumentError('use setErrorState() to set the state to ERROR');
-    }
-    if (state == CacheState.VALID) {
-      throw new ArgumentError('use setValue() to set the state to VALID');
-    }
-    _validateStateChange(descriptor, state);
-    if (state == CacheState.INVALID) {
-      ResultData data = _resultMap[descriptor];
-      if (data != null) {
-        bool canUseDelta =
-            _gatherResultsInvalidatedByDelta(descriptor, delta, 0);
-        if (!canUseDelta) {
-          delta = null;
-        }
-        _invalidate(nextVisitId++, descriptor, delta, 0);
-      }
-    } else {
-      ResultData data = getResultData(descriptor);
-      data.state = state;
-      if (state != CacheState.IN_PROCESS) {
-        //
-        // If the state is in-process, we can leave the current value in the
-        // cache for any 'get' methods to access.
-        //
-        data.value = descriptor.defaultValue;
-      }
-    }
-  }
-
-  /**
-   * Set the value of the result represented by the given [descriptor] to the
-   * given [value].
-   */
-  void setValue<V>(ResultDescriptor<V> descriptor, V value,
-      List<TargetedResult> dependedOn) {
-//    {
-//      String valueStr = '$value';
-//      if (valueStr.length > 20) {
-//        valueStr = valueStr.substring(0, 20) + '...';
-//      }
-//      valueStr = valueStr.replaceAll('\n', '\\n');
-//      print(
-//          'setValue $descriptor for $target value=$valueStr dependedOn=$dependedOn');
-//    }
-    _validateStateChange(descriptor, CacheState.VALID);
-    TargetedResult thisResult = new TargetedResult(target, descriptor);
-    if (_partition != null) {
-      _partition.resultStored(thisResult, value);
-    }
-    ResultData data = getResultData(descriptor);
-    _setDependedOnResults(data, thisResult, dependedOn);
-    if (data.state == CacheState.FLUSHED) {
-      int count = recomputedCounts[descriptor] ?? 0;
-      recomputedCounts[descriptor] = count + 1;
-    }
-    data.state = CacheState.VALID;
-    data.value = value ?? descriptor.defaultValue;
-  }
-
-  /**
-   * If the result represented by the given [descriptor] is valid, set
-   * it to the given [value], keep its dependency, and if [invalidateDependent]
-   * invalidate all the dependent result.
-   */
-  void setValueIncremental(
-      ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
-    ResultData data = getResultData(descriptor);
-    if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
-      data.value = value;
-    }
-    if (invalidateDependent) {
-      _invalidateDependentResults(nextVisitId++, data, null, 0);
-    }
-  }
-
-  @override
-  String toString() {
-    StringBuffer buffer = new StringBuffer();
-    _writeOn(buffer);
-    return buffer.toString();
-  }
-
-  /**
-   * Visit the given [result] and all results that depend on it, and
-   * ask [delta] to gather changes. Return `true` if the [delta] can be used
-   * to perform limited invalidation, or `false` if the changes collection
-   * process does not stop (should not happen).
-   */
-  bool _gatherResultsInvalidatedByDelta(
-      ResultDescriptor result, Delta delta, int level) {
-    if (delta == null) {
-      return false;
-    }
-    if (!delta.shouldGatherChanges) {
-      return true;
-    }
-    for (int i = 0; i < 64; i++) {
-      bool hasVisitChanges = false;
-      _visitResults(nextVisitId++, result,
-          (AnalysisTarget target, ResultData data) {
-        bool hasDeltaChanges = delta.gatherChanges(
-            _partition.context, target, data.descriptor, data.value);
-        if (hasDeltaChanges) {
-          hasVisitChanges = true;
-        }
-      });
-      delta.gatherEnd();
-      if (!hasVisitChanges) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Return the value of the flag with the given [index].
-   */
-  bool _getFlag(int index) => BooleanArray.get(_flags, index);
-
-  /**
-   * Invalidate the result represented by the given [descriptor] and propagate
-   * invalidation to other results that depend on it.
-   */
-  void _invalidate(
-      int id, ResultDescriptor descriptor, Delta delta, int level) {
-    ResultData thisData = _resultMap[descriptor];
-    if (thisData == null) {
-      return;
-    }
-    // Stop if already validated.
-    if (delta != null) {
-      if (thisData.visitId == id) {
-        return;
-      }
-      thisData.visitId = id;
-    }
-    // Ask the delta to validate.
-    DeltaResult deltaResult = null;
-    if (delta != null) {
-      deltaResult = delta.validate(
-          _partition.context, target, descriptor, thisData.value);
-      if (deltaResult == DeltaResult.STOP) {
-        return;
-      }
-    }
-//    if (deltaResult != null) {
-//      String indent = '  ' * level;
-//      String deltaResultName = deltaResult.toString().split('.').last;
-//      print('[$id]$indent$deltaResultName $descriptor for $target');
-//    }
-    if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
-      delta = null;
-    }
-    if (deltaResult == DeltaResult.INVALIDATE_KEEP_DEPENDENCIES) {
-      thisData.value = descriptor.defaultValue;
-      thisData.state = CacheState.INVALID;
-    } else if (deltaResult == null ||
-        deltaResult == DeltaResult.INVALIDATE ||
-        deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
-      _resultMap.remove(descriptor);
-      // Stop depending on other results.
-      {
-        TargetedResult thisResult = new TargetedResult(target, descriptor);
-        List<AnalysisCache> caches = _partition.containingCaches;
-        int cacheLength = caches.length;
-        List<TargetedResult> results = thisData.dependedOnResults;
-        int resultLength = results.length;
-        for (int i = 0; i < resultLength; i++) {
-          TargetedResult dependedOnResult = results[i];
-          for (int j = 0; j < cacheLength; j++) {
-            AnalysisCache cache = caches[j];
-            CacheEntry entry = cache.get(dependedOnResult.target);
-            if (entry != null) {
-              ResultData data =
-                  entry.getResultDataOrNull(dependedOnResult.result);
-              if (data != null) {
-                data.dependentResults.remove(thisResult);
-              }
-            }
-          }
-        }
-      }
-//      if (deltaResult == null) {
-//        String indent = '  ' * level;
-//        print('[$id]$indent invalidate $descriptor for $target');
-//      }
-    }
-    // Invalidate results that depend on this result.
-    _invalidateDependentResults(id, thisData, delta, level + 1);
-    // If empty and not explicitly added, remove the entry altogether.
-    if (_resultMap.isEmpty && !explicitlyAdded) {
-      CacheEntry entry = _partition.entryMap.remove(target);
-      if (entry != null) {
-        entry.dispose();
-      }
-      _partition._removeIfSource(target);
-    }
-    // Notify controller.
-    if (deltaResult != DeltaResult.KEEP_CONTINUE) {
-      _partition.onResultInvalidated
-          .add(new InvalidatedResult(this, descriptor, thisData.value));
-    }
-  }
-
-  /**
-   * Invalidates all the results of this entry, with propagation.
-   */
-  void _invalidateAll() {
-    List<ResultDescriptor> results = _resultMap.keys.toList();
-    int length = results.length;
-    for (int i = 0; i < length; i++) {
-      ResultDescriptor result = results[i];
-      _invalidate(nextVisitId++, result, null, 0);
-    }
-  }
-
-  /**
-   * Invalidate results that depend on [thisData].
-   */
-  void _invalidateDependentResults(
-      int id, ResultData thisData, Delta delta, int level) {
-    // It is necessary to copy the results to a list to avoid a concurrent
-    // modification of the set of dependent results.
-    List<AnalysisCache> caches = _partition.containingCaches;
-    int cacheLength = caches.length;
-    List<TargetedResult> dependentResults = thisData.dependentResults.toList();
-    int resultLength = dependentResults.length;
-    for (int i = 0; i < resultLength; i++) {
-      TargetedResult dependentResult = dependentResults[i];
-      for (int j = 0; j < cacheLength; j++) {
-        AnalysisCache cache = caches[j];
-        CacheEntry entry = cache.get(dependentResult.target);
-        if (entry != null) {
-          entry._invalidate(id, dependentResult.result, delta, level);
-        }
-      }
-    }
-  }
-
-  /**
-   * Set the [dependedOn] on which this result depends.
-   */
-  void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
-      List<TargetedResult> dependedOn) {
-    List<AnalysisCache> caches = _partition.containingCaches;
-    int cacheLength = caches.length;
-
-    List<TargetedResult> oldResults = thisData.dependedOnResults;
-    int oldLength = oldResults.length;
-    for (int i = 0; i < oldLength; i++) {
-      TargetedResult dependedOnResult = oldResults[i];
-      for (int j = 0; j < cacheLength; j++) {
-        AnalysisCache cache = caches[j];
-        CacheEntry entry = cache.get(dependedOnResult.target);
-        if (entry != null) {
-          ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
-          if (data != null) {
-            data.dependentResults.remove(thisResult);
-          }
-        }
-      }
-    }
-    thisData.dependedOnResults = dependedOn;
-    int newLength = dependedOn.length;
-    for (int i = 0; i < newLength; i++) {
-      TargetedResult dependedOnResult = dependedOn[i];
-      for (int j = 0; j < cacheLength; j++) {
-        AnalysisCache cache = caches[j];
-        CacheEntry entry = cache.get(dependedOnResult.target);
-        if (entry != null) {
-          ResultData data = entry.getResultData(dependedOnResult.result);
-          data.dependentResults.add(thisResult);
-        }
-      }
-    }
-  }
-
-  /**
-   * Set states of the given and dependent results to [CacheState.ERROR] and
-   * their values to the corresponding default values
-   */
-  void _setErrorState(ResultDescriptor descriptor, CaughtException exception) {
-    ResultData thisData = getResultData(descriptor);
-    // Set the error state.
-    _exception = exception;
-    thisData.state = CacheState.ERROR;
-    thisData.value = descriptor.defaultValue;
-    // Propagate the error state.
-    List<AnalysisCache> caches = _partition.containingCaches;
-    int cacheLength = caches.length;
-    thisData.dependentResults.forEach((TargetedResult dependentResult) {
-      for (int i = 0; i < cacheLength; i++) {
-        AnalysisCache cache = caches[i];
-        CacheEntry entry = cache.get(dependentResult.target);
-        if (entry != null) {
-          entry._setErrorState(dependentResult.result, exception);
-        }
-      }
-    });
-  }
-
-  /**
-   * Set the value of the flag with the given [index] to the given [value].
-   */
-  void _setFlag(int index, bool value) {
-    _flags = BooleanArray.set(_flags, index, value);
-  }
-
-  /**
-   * If the state of the value described by the given [descriptor] is changing
-   * from ERROR to anything else, capture the information. This is an attempt to
-   * discover the underlying cause of a long-standing bug.
-   */
-  void _validateStateChange(ResultDescriptor descriptor, CacheState newState) {
-    // TODO(brianwilkerson) Decide whether we still want to capture this data.
-//    if (descriptor != CONTENT) {
-//      return;
-//    }
-//    ResultData data = resultMap[CONTENT];
-//    if (data != null && data.state == CacheState.ERROR) {
-//      String message =
-//          'contentState changing from ${data.state} to $newState';
-//      InstrumentationBuilder builder =
-//          Instrumentation.builder2('CacheEntry-validateStateChange');
-//      builder.data3('message', message);
-//      //builder.data('source', source.getFullName());
-//      builder.record(new CaughtException(new AnalysisException(message), null));
-//      builder.log();
-//    }
-  }
-
-  /**
-   * Call [visitor] for the result described by the given [descriptor] and all
-   * results that depend on directly or indirectly. Each result is visited
-   * only once.
-   */
-  void _visitResults(
-      int id, ResultDescriptor descriptor, CacheResultVisitor visitor) {
-    ResultData thisData = _resultMap[descriptor];
-    if (thisData == null) {
-      return;
-    }
-    // Stop if already visited.
-    if (thisData.visitId == id) {
-      return;
-    }
-    thisData.visitId = id;
-    // Visit this result.
-    visitor(target, thisData);
-    // Visit results that depend on this result.
-    List<AnalysisCache> caches = _partition.containingCaches;
-    int cacheLength = caches.length;
-    List<TargetedResult> dependentResults = thisData.dependentResults.toList();
-    int resultLength = dependentResults.length;
-    for (int i = 0; i < resultLength; i++) {
-      TargetedResult dependentResult = dependentResults[i];
-      for (int j = 0; j < cacheLength; j++) {
-        AnalysisCache cache = caches[j];
-        CacheEntry entry = cache.get(dependentResult.target);
-        if (entry != null) {
-          entry._visitResults(id, dependentResult.result, visitor);
-        }
-      }
-    }
-  }
-
-  /**
-   * Write a textual representation of this entry to the given [buffer]. The
-   * result should only be used for debugging purposes.
-   */
-  void _writeOn(StringBuffer buffer) {
-    buffer.write('time = ');
-    buffer.write(modificationTime);
-    List<ResultDescriptor> results = _resultMap.keys.toList();
-    results.sort((ResultDescriptor first, ResultDescriptor second) =>
-        first.toString().compareTo(second.toString()));
-    for (ResultDescriptor result in results) {
-      ResultData data = _resultMap[result];
-      buffer.write('; ');
-      buffer.write(result.toString());
-      buffer.write(' = ');
-      buffer.write(data.state);
-    }
-  }
-}
-
-/**
- * An object that controls flushing of analysis results from the cache.
- */
-class CacheFlushManager<T> {
-  final IsPriorityAnalysisTarget isPriorityAnalysisTarget;
-  final ResultCachingPolicy policy;
-  final int maxActiveSize;
-  final int maxIdleSize;
-
-  /**
-   * A map of the stored [TargetedResult] to their sizes.
-   */
-  final HashMap<TargetedResult, int> resultSizeMap =
-      new HashMap<TargetedResult, int>();
-
-  /**
-   * A linked set containing the most recently accessed results with the most
-   * recently used at the end of the list. When more results are added than the
-   * maximum size allowed then the least recently used results will be flushed
-   * from the cache.
-   */
-  final LinkedHashSet<TargetedResult> recentlyUsed =
-      new LinkedHashSet<TargetedResult>();
-
-  /**
-   * The current size of stored results.
-   */
-  int currentSize = 0;
-
-  /**
-   * The current maximum cache size.
-   */
-  int maxSize;
-
-  CacheFlushManager(ResultCachingPolicy policy, this.isPriorityAnalysisTarget)
-      : policy = policy,
-        maxActiveSize = policy.maxActiveSize,
-        maxIdleSize = policy.maxIdleSize,
-        maxSize = policy.maxActiveSize;
-
-  /**
-   * If [currentSize] is already less than [maxSize], returns an empty list.
-   * Otherwise returns [TargetedResult]s to flush from the cache to make
-   * [currentSize] less or equal to [maxSize].
-   *
-   * Results for priority files are never flushed, so this method might leave
-   * [currentSize] greater than [maxSize].
-   */
-  List<TargetedResult> flushToSize() {
-    // If still under the cap, done.
-    if (currentSize <= maxSize) {
-      return const <TargetedResult>[];
-    }
-    // Flush results until we are under the cap.
-    List<TargetedResult> resultsToFlush = <TargetedResult>[];
-    for (TargetedResult result in recentlyUsed) {
-      if (isPriorityAnalysisTarget(result.target)) {
-        continue;
-      }
-      resultsToFlush.add(result);
-      int size = resultSizeMap.remove(result);
-      assert(size != null);
-      currentSize -= size;
-      if (currentSize <= maxSize) {
-        break;
-      }
-    }
-    recentlyUsed.removeAll(resultsToFlush);
-    return resultsToFlush;
-  }
-
-  /**
-   * Notifies this manager that the corresponding analysis context is active.
-   */
-  void madeActive() {
-    maxSize = maxActiveSize;
-  }
-
-  /**
-   * Notifies this manager that the corresponding analysis context is idle.
-   * Returns [TargetedResult]s that should be flushed from the cache.
-   */
-  List<TargetedResult> madeIdle() {
-    maxSize = maxIdleSize;
-    return flushToSize();
-  }
-
-  /**
-   * Records that the given [result] was just read from the cache.
-   */
-  void resultAccessed(TargetedResult result) {
-    if (recentlyUsed.remove(result)) {
-      recentlyUsed.add(result);
-    }
-  }
-
-  /**
-   * Records that the given [newResult] and [newValue] were stored to the cache.
-   * Returns [TargetedResult]s that should be flushed from the cache.
-   */
-  List<TargetedResult> resultStored(TargetedResult newResult, T newValue) {
-    if (!recentlyUsed.remove(newResult)) {
-      int size = policy.measure(newValue);
-      resultSizeMap[newResult] = size;
-      currentSize += size;
-    }
-    recentlyUsed.add(newResult);
-    return flushToSize();
-  }
-
-  /**
-   * Records that the given [target] was just removed from to the cache.
-   */
-  void targetRemoved(AnalysisTarget target) {
-    List<TargetedResult> resultsToRemove = <TargetedResult>[];
-    for (TargetedResult result in recentlyUsed) {
-      if (result.target == target) {
-        resultsToRemove.add(result);
-        int size = resultSizeMap.remove(result);
-        assert(size != null);
-        currentSize -= size;
-      }
-    }
-    recentlyUsed.removeAll(resultsToRemove);
-  }
-}
-
-/**
- * A single partition in an LRU cache of information related to analysis.
- */
 abstract class CachePartition {
-  /**
-   * The context that owns this partition. Multiple contexts can reference a
-   * partition, but only one context can own it.
-   */
   final InternalAnalysisContext context;
-
-  /**
-   * A list of the caches that contain this partition. This includes the cache
-   * associated with the context that owns this partition.
-   */
-  final List<AnalysisCache> containingCaches = <AnalysisCache>[];
-
-  /**
-   * A table mapping caching policies to the cache flush managers.
-   */
-  final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap =
-      new HashMap<ResultCachingPolicy, CacheFlushManager>();
-
-  /**
-   * The [StreamController] reporting [InvalidatedResult]s.
-   */
-  final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
-      new ReentrantSynchronousStream<InvalidatedResult>();
-
-  /**
-   * A table mapping the targets belonging to this partition to the information
-   * known about those targets.
-   */
-  final HashMap<AnalysisTarget, CacheEntry> entryMap =
-      new HashMap<AnalysisTarget, CacheEntry>();
-
-  /**
-   * A set of the [Source] targets.
-   */
-  final HashSet<Source> sources = new HashSet<Source>();
-
-  /**
-   * A table mapping full paths to lists of [Source]s with these full paths.
-   */
-  final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
-
-  /**
-   * Initialize a newly created cache partition, belonging to the given
-   * [context].
-   */
   CachePartition(this.context);
-
-  /**
-   * Specify whether a context that uses this partition is being analyzed.
-   */
-  set isActive(bool active) {
-    for (CacheFlushManager manager in _flushManagerMap.values) {
-      if (active) {
-        manager.madeActive();
-      } else {
-        List<TargetedResult> resultsToFlush = manager.madeIdle();
-        _flushResults(resultsToFlush);
-      }
-    }
-  }
-
-  /**
-   * Notifies the partition that the client is going to stop using it.
-   */
-  void dispose() {
-    for (CacheEntry entry in entryMap.values) {
-      entry.dispose();
-    }
-    entryMap.clear();
-    sources.clear();
-    pathToSource.clear();
-  }
-
-  /**
-   * Flush results that satisfy the given [filter].
-   */
-  void flush(FlushResultFilter filter) {
-    for (CacheEntry entry in entryMap.values) {
-      entry.flush(filter);
-    }
-  }
-
-  /**
-   * Return the entry associated with the given [target].
-   */
-  CacheEntry get(AnalysisTarget target) => entryMap[target];
-
-  /**
-   * Return [Source]s whose full path is equal to the given [path].
-   * Maybe empty, but not `null`.
-   */
-  List<Source> getSourcesWithFullName(String path) {
-    List<Source> sources = pathToSource[path];
-    return sources ?? const <Source>[];
-  }
-
-  /**
-   * Return `true` if this partition is responsible for the given [target].
-   */
-  bool isResponsibleFor(AnalysisTarget target);
-
-  /**
-   * Return an iterator returning all of the map entries mapping targets to
-   * cache entries.
-   */
-  MapIterator<AnalysisTarget, CacheEntry> iterator() =>
-      new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
-
-  /**
-   * Puts the given [entry] into the partition.
-   */
-  void put(CacheEntry entry) {
-    AnalysisTarget target = entry.target;
-    if (entry._partition != null) {
-      throw new StateError(
-          'The entry for $target is already in ${entry._partition}');
-    }
-    entry._partition = this;
-    entry.fixExceptionState();
-    entryMap[target] = entry;
-    _addIfSource(target);
-  }
-
-  /**
-   * Remove all information related to the given [target] from this partition.
-   * Return the entry associated with the target, or `null` if there was cache
-   * entry for the target.
-   */
-  CacheEntry remove(AnalysisTarget target) {
-    for (CacheFlushManager flushManager in _flushManagerMap.values) {
-      flushManager.targetRemoved(target);
-    }
-    CacheEntry entry = entryMap.remove(target);
-    if (entry != null) {
-      entry._invalidateAll();
-    }
-    _removeIfSource(target);
-    return entry;
-  }
-
-  /**
-   * Records that a value of the result described by the given [descriptor]
-   * for the given [target] was just read from the cache.
-   */
-  void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) {
-    CacheFlushManager flushManager = _getFlushManager(descriptor);
-    TargetedResult result = new TargetedResult(target, descriptor);
-    flushManager.resultAccessed(result);
-  }
-
-  /**
-   * Records that the given [result] was just stored into the cache.
-   */
-  void resultStored(TargetedResult result, Object value) {
-    CacheFlushManager flushManager = _getFlushManager(result.result);
-    List<TargetedResult> resultsToFlush =
-        flushManager.resultStored(result, value);
-    _flushResults(resultsToFlush);
-  }
-
-  /**
-   * Return the number of targets that are mapped to cache entries.
-   */
-  int size() => entryMap.length;
-
-  /**
-   * If the given [target] is a [Source], adds it to [sources].
-   */
-  void _addIfSource(AnalysisTarget target) {
-    if (target is Source) {
-      sources.add(target);
-      String fullName = target.fullName;
-      pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
-    }
-  }
-
-  /**
-   * Flush the given [resultsToFlush].
-   */
-  void _flushResults(List<TargetedResult> resultsToFlush) {
-    for (TargetedResult result in resultsToFlush) {
-      CacheEntry entry = get(result.target);
-      if (entry != null) {
-        ResultData data = entry._resultMap[result.result];
-        if (data != null) {
-          data.flush();
-        }
-      }
-    }
-  }
-
-  /**
-   * Return the [CacheFlushManager] for the given [descriptor], not `null`.
-   */
-  CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
-    ResultCachingPolicy policy = descriptor.cachingPolicy;
-    if (identical(policy, DEFAULT_CACHING_POLICY) ||
-        context.analysisOptions.disableCacheFlushing) {
-      return UnlimitedCacheFlushManager.INSTANCE;
-    }
-    CacheFlushManager manager = _flushManagerMap[policy];
-    if (manager == null) {
-      manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget);
-      _flushManagerMap[policy] = manager;
-    }
-    return manager;
-  }
-
-  bool _isPriorityAnalysisTarget(AnalysisTarget target) {
-    Source source = target.source;
-    return source != null && context.prioritySources.contains(source);
-  }
-
-  /**
-   * If the given [target] is a [Source], remove it from the list of [sources].
-   */
-  void _removeIfSource(AnalysisTarget target) {
-    if (target is Source) {
-      sources.remove(target);
-      String path = target.fullName;
-      List<Source> pathSources = pathToSource[path];
-      if (pathSources != null) {
-        pathSources.remove(target);
-        if (pathSources.isEmpty) {
-          pathToSource.remove(path);
-        }
-      }
-    }
-  }
 }
 
-/**
- * The description for a change.
- */
-class Delta {
-  final Source source;
-
-  Delta(this.source);
-
-  /**
-   * Return `true` if this delta needs cache walking to gather additional
-   * changes before it can be used to [validate].  In this case [gatherChanges]
-   * is invoked for every targeted result in transitive dependencies, and
-   * [gatherEnd] is invoked after cache walking is done.
-   */
-  bool get shouldGatherChanges => false;
-
-  /**
-   * This method is called during a cache walk, so that the delta can gather
-   * additional changes to which are caused by the changes it already knows
-   * about.  Return `true` if a new change was added, so that one more cache
-   * walk will be performed (to include changes that depend on results which we
-   * decided to be changed later in the previous cache walk).
-   */
-  bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
-      ResultDescriptor descriptor, Object value) {
-    return false;
-  }
-
-  /**
-   * The current cache results visit is done.
-   */
-  void gatherEnd() {}
-
-  /**
-   * Check whether this delta affects the result described by the given
-   * [descriptor] and [target]. The current [value] of the result is provided.
-   */
-  DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
-      ResultDescriptor descriptor, Object value) {
-    return DeltaResult.INVALIDATE;
-  }
-}
-
-/**
- * The possible results of validating analysis results against a [Delta].
- */
-enum DeltaResult {
-  /**
-   * Invalidate this result and continue visiting dependent results
-   * with this [Delta]. Remove the result and all its dependencies.
-   */
-  INVALIDATE,
-
-  /**
-   * Invalidate this result and continue visiting dependent results
-   * with this [Delta]. Keep the dependencies of this result.
-   */
-  INVALIDATE_KEEP_DEPENDENCIES,
-
-  /**
-   * Invalidate this result and stop using this [Delta], so unconditionally
-   * invalidate all the dependent results.
-   */
-  INVALIDATE_NO_DELTA,
-
-  /**
-   * Keep this result and continue validating dependent results
-   * with this [Delta].
-   */
-  KEEP_CONTINUE,
-
-  /**
-   * Keep this result and stop visiting results that depend on this one.
-   */
-  STOP
-}
-
-/**
- * [InvalidatedResult] describes an invalidated result.
- */
-class InvalidatedResult<V> {
-  /**
-   * The target in which the result was invalidated.
-   */
-  final CacheEntry entry;
-
-  /**
-   * The descriptor of the result which was invalidated.
-   */
-  final ResultDescriptor<V> descriptor;
-
-  /**
-   * The value of the result before it was invalidated, may be the default
-   * value if the result was flushed.
-   */
-  final V value;
-
-  InvalidatedResult(this.entry, this.descriptor, this.value);
-
-  @override
-  String toString() => '$descriptor of ${entry.target}';
-}
-
-/**
- * A cache partition that contains all of the targets in a single package.
- */
-class PackageCachePartition extends CachePartition {
-  /**
-   * The root of the directory representing the package.
-   */
-  final Folder packageRoot;
-
-  /**
-   * Initialize a newly created cache partition, belonging to the given
-   * [context].
-   */
-  PackageCachePartition(InternalAnalysisContext context, this.packageRoot)
-      : super(context);
-
-  @override
-  bool isResponsibleFor(AnalysisTarget target) {
-    Source source = target.source;
-    return source != null && packageRoot.contains(source.fullName);
-  }
-}
-
-/**
- * A Stream-like interface, which broadcasts events synchronously.
- * If a second event is fired while delivering a first event, then the second
- * event will be delivered first, and then delivering of the first will be
- * continued.
- */
-class ReentrantSynchronousStream<T> {
-  final List<Function> listeners = <Function>[];
-
-  /**
-   * Send the given [event] to the stream.
-   */
-  void add(T event) {
-    List<Function> listeners = this.listeners.toList();
-    for (Function listener in listeners) {
-      listener(event);
-    }
-  }
-
-  /**
-   * Listen for the events in this stream.
-   * Note that if the [listener] fires a new event, then the [listener] will be
-   * invoked again before returning from the [add] invocation.
-   */
-  ReentrantSynchronousStreamSubscription<T> listen(void listener(T event)) {
-    listeners.add(listener);
-    return new ReentrantSynchronousStreamSubscription<T>(this, listener);
-  }
-}
-
-/**
- * A subscription on events from a [ReentrantSynchronousStream].
- */
-class ReentrantSynchronousStreamSubscription<T> {
-  final ReentrantSynchronousStream<T> _stream;
-  final Function _listener;
-
-  ReentrantSynchronousStreamSubscription(this._stream, this._listener);
-
-  /**
-   * Cancels this subscription.
-   * It will no longer receive events.
-   */
-  void cancel() {
-    _stream.listeners.remove(_listener);
-  }
-}
-
-/**
- * The data about a single analysis result that is stored in a [CacheEntry].
- */
-// TODO(brianwilkerson) Consider making this a generic class so that the value
-// can be typed.
-class ResultData {
-  /**
-   * The [ResultDescriptor] this result is for.
-   */
-  final ResultDescriptor descriptor;
-
-  /**
-   * The state of the cached value.
-   */
-  CacheState state;
-
-  /**
-   * The value being cached, or the default value for the result if there is no
-   * value (for example, when the [state] is [CacheState.INVALID]).
-   */
-  Object value;
-
-  /**
-   * The identifier of the most recent visiting process. We use it to visit
-   * every result only once.
-   */
-  int visitId = -1;
-
-  /**
-   * A list of the results on which this result depends.
-   */
-  List<TargetedResult> dependedOnResults = <TargetedResult>[];
-
-  /**
-   * A list of the results that depend on this result.
-   */
-  Set<TargetedResult> dependentResults = new Set<TargetedResult>();
-
-  /**
-   * Initialize a newly created result holder to represent the value of data
-   * described by the given [descriptor].
-   */
-  ResultData(this.descriptor) {
-    state = CacheState.INVALID;
-    value = descriptor.defaultValue;
-  }
-
-  /**
-   * Flush this value.
-   */
-  void flush() {
-    state = CacheState.FLUSHED;
-    value = descriptor.defaultValue;
-  }
-}
-
-/**
- * A cache partition that contains all of the targets in the SDK.
- */
 class SdkCachePartition extends CachePartition {
-  /**
-   * Initialize a newly created cache partition, belonging to the given
-   * [context].
-   */
   SdkCachePartition(InternalAnalysisContext context) : super(context);
-
-  @override
-  bool isResponsibleFor(AnalysisTarget target) {
-    if (target is AnalysisContextTarget) {
-      return true;
-    }
-    Source source = target.source;
-    return source != null && source.isInSystemLibrary;
-  }
-}
-
-/**
- * A cache partition that contains all targets not contained in other partitions.
- */
-class UniversalCachePartition extends CachePartition {
-  /**
-   * Initialize a newly created cache partition, belonging to the given
-   * [context].
-   */
-  UniversalCachePartition(InternalAnalysisContext context) : super(context);
-
-  @override
-  bool isResponsibleFor(AnalysisTarget target) => true;
-}
-
-/**
- * [CacheFlushManager] that does nothing, results are never flushed.
- */
-class UnlimitedCacheFlushManager extends CacheFlushManager {
-  static final CacheFlushManager INSTANCE = new UnlimitedCacheFlushManager();
-
-  UnlimitedCacheFlushManager() : super(DEFAULT_CACHING_POLICY, (_) => false);
-
-  @override
-  void resultAccessed(TargetedResult result) {}
-
-  @override
-  List<TargetedResult> resultStored(TargetedResult newResult, newValue) {
-    return const <TargetedResult>[];
-  }
-
-  @override
-  void targetRemoved(AnalysisTarget target) {}
 }
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 418bb41..876243d 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/plugin/resolver_provider.dart';
 import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/driver.dart';
 
 /**
  * An [AnalysisContext] in which analysis can be performed.
@@ -46,23 +45,6 @@
    */
   DeclaredVariables _declaredVariables = new DeclaredVariables();
 
-  @override
-  final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
-      new ReentrantSynchronousStream<InvalidatedResult>();
-
-  ReentrantSynchronousStreamSubscription onResultInvalidatedSubscription = null;
-
-  /**
-   * A list of all [WorkManager]s used by this context.
-   */
-  @override
-  final List<WorkManager> workManagers = <WorkManager>[];
-
-  /**
-   * The analysis driver used to perform analysis.
-   */
-  AnalysisDriver driver;
-
   /**
    * The [TypeProvider] for this context, `null` if not yet created.
    */
@@ -198,11 +180,6 @@
   }
 
   @override
-  Stream<SourcesChangedEvent> get onSourcesChanged {
-    throw UnimplementedError();
-  }
-
-  @override
   List<Source> get prioritySources {
     throw UnimplementedError();
   }
@@ -263,11 +240,6 @@
   }
 
   @override
-  bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
-    throw UnimplementedError();
-  }
-
-  @override
   void addListener(AnalysisListener listener) {
     throw UnimplementedError();
   }
@@ -323,11 +295,6 @@
     throw UnimplementedError();
   }
 
-  @override
-  V computeResult<V>(AnalysisTarget target, ResultDescriptor<V> descriptor) {
-    throw UnimplementedError();
-  }
-
   /**
    * Create an analysis cache based on the given source [factory].
    */
@@ -349,22 +316,11 @@
   }
 
   @override
-  CacheEntry getCacheEntry(AnalysisTarget target) {
-    throw UnimplementedError();
-  }
-
-  @override
   CompilationUnitElement getCompilationUnitElement(
       Source unitSource, Source librarySource) {
     throw UnimplementedError();
   }
 
-  @deprecated
-  @override
-  V getConfigurationData<V>(ResultDescriptor<V> key) {
-    throw UnimplementedError();
-  }
-
   @override
   TimestampedData<String> getContents(Source source) {
     throw UnimplementedError();
@@ -456,11 +412,6 @@
   }
 
   @override
-  V getResult<V>(AnalysisTarget target, ResultDescriptor<V> result) {
-    throw UnimplementedError();
-  }
-
-  @override
   List<Source> getSourcesWithFullName(String path) {
     throw UnimplementedError();
   }
@@ -495,17 +446,6 @@
   }
 
   @override
-  Stream<ResultChangedEvent> onResultChanged(ResultDescriptor descriptor) {
-    throw UnimplementedError();
-  }
-
-  @override
-  @deprecated
-  Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) {
-    throw UnimplementedError();
-  }
-
-  @override
   CompilationUnit parseCompilationUnit(Source source) {
     throw UnimplementedError();
   }
@@ -543,12 +483,6 @@
     throw UnimplementedError();
   }
 
-  @deprecated
-  @override
-  void setConfigurationData(ResultDescriptor key, Object data) {
-    throw UnimplementedError();
-  }
-
   @override
   void setContents(Source source, String contents) {
     throw UnimplementedError();
diff --git a/pkg/analyzer/lib/src/dart/analysis/ddc.dart b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
index ef6dceb..f526171 100644
--- a/pkg/analyzer/lib/src/dart/analysis/ddc.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -20,7 +21,6 @@
 import 'package:analyzer/src/summary/resynthesize.dart';
 import 'package:analyzer/src/summary/summarize_ast.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:analyzer/src/summary2/informative_data.dart';
 import 'package:analyzer/src/summary2/link.dart' as summary2;
 import 'package:analyzer/src/summary2/linked_bundle_context.dart' as summary2;
@@ -247,9 +247,7 @@
 
     var dartCore = elementFactory.libraryOfUri('dart:core');
     var dartAsync = elementFactory.libraryOfUri('dart:async');
-    var typeProvider = SummaryTypeProvider()
-      ..initializeCore(dartCore)
-      ..initializeAsync(dartAsync);
+    var typeProvider = TypeProviderImpl(dartCore, dartAsync);
     context.typeProvider = typeProvider;
 
     dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index d9adea9..a637158 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -96,7 +96,7 @@
   static int allowedNumberOfContextsToWrite = 10;
 
   /// Whether summary2 should be used to resynthesize elements.
-  static bool useSummary2 = false;
+  static bool useSummary2 = true;
 
   /// The scheduler that schedules analysis work in this, and possibly other
   /// analysis drivers.
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 8d45ba7..02b4b51 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -555,10 +554,7 @@
   visitClassDeclaration(ClassDeclaration node) {
     _addSubtypeForClassDeclaration(node);
     if (node.extendsClause == null) {
-      ClassElement objectElement = resolutionMap
-          .elementDeclaredByClassDeclaration(node)
-          .supertype
-          ?.element;
+      ClassElement objectElement = node.declaredElement.supertype?.element;
       recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
           node.name.offset, 0, true);
     }
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 3a8ad34..a8c8650 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -22,6 +22,8 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/legacy_type_asserter.dart';
@@ -68,7 +70,7 @@
   final AnalysisContext _context;
   final ElementResynthesizer _resynthesizer;
   final LinkedElementFactory _elementFactory;
-  TypeProvider _typeProvider;
+  TypeProviderImpl _typeProvider;
 
   final TypeSystem _typeSystem;
   LibraryElement _libraryElement;
@@ -134,13 +136,9 @@
     FeatureSet featureSet = units[_library].featureSet;
     _typeProvider = _context.typeProvider;
     if (featureSet.isEnabled(Feature.non_nullable)) {
-      if (_typeProvider is! NonNullableTypeProvider) {
-        _typeProvider = NonNullableTypeProvider.from(_typeProvider);
-      }
+      _typeProvider = _typeProvider.withNullability(NullabilitySuffix.none);
     } else {
-      if (_typeProvider is NonNullableTypeProvider) {
-        _typeProvider = TypeProviderImpl.from(_typeProvider);
-      }
+      _typeProvider = _typeProvider.withNullability(NullabilitySuffix.star);
     }
     units.forEach((file, unit) {
       _validateFeatureSet(unit, featureSet);
@@ -537,11 +535,10 @@
             directive.prefix?.staticElement = importElement.prefix;
             Source source = importElement.importedLibrary?.source;
             if (source != null && !_isLibrarySource(source)) {
-              ErrorCode errorCode = importElement.isDeferred
-                  ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
-                  : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
               libraryErrorReporter.reportErrorForNode(
-                  errorCode, directive.uri, [directive.uri]);
+                  CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
+                  directive.uri,
+                  [directive.uri]);
             }
           }
         }
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 99bfc35..56a3aed 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisOptions;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
@@ -24,7 +25,6 @@
 import 'package:analyzer/src/summary/link.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:analyzer/src/summary2/link.dart' as link2;
 import 'package:analyzer/src/summary2/linked_bundle_context.dart';
 import 'package:analyzer/src/summary2/linked_element_factory.dart';
@@ -416,9 +416,7 @@
 
     var dartCore = elementFactory.libraryOfUri('dart:core');
     var dartAsync = elementFactory.libraryOfUri('dart:async');
-    var typeProvider = SummaryTypeProvider()
-      ..initializeCore(dartCore)
-      ..initializeAsync(dartAsync);
+    var typeProvider = TypeProviderImpl(dartCore, dartAsync);
     analysisContext.typeProvider = typeProvider;
 
     dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 9da05f9..da2e4d0 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -290,6 +290,12 @@
           }
         }
       }
+    } else if (element is ExtensionElement) {
+      if (node is ExtensionDeclaration) {
+        if (_hasOffset(node.name)) {
+          result = node;
+        }
+      }
     } else if (element is FieldElement) {
       if (node is EnumConstantDeclaration) {
         if (_hasOffset(node.name)) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 6b75d09..2857311 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart' as driver;
 import 'package:analyzer/src/dart/analysis/uri_converter.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index fc942c1..2b09546 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -9189,6 +9189,10 @@
   }
 
   @override
+  bool get isNullAware =>
+      spreadOperator.type == TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
+
+  @override
   E accept<E>(AstVisitor<E> visitor) {
     return visitor.visitSpreadElement(this);
   }
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 53e8356..dd26599 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -111,7 +111,7 @@
     if (arguments[0] is NamedExpression) {
       return false;
     }
-    if (!identical(argumentValues[0].type, typeProvider.stringType)) {
+    if (argumentValues[0].type != typeProvider.stringType) {
       return false;
     }
     if (argumentCount == 2) {
@@ -122,8 +122,8 @@
         }
         ParameterizedType defaultValueType =
             namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
-        if (!(identical(defaultValueType, expectedDefaultValueType) ||
-            identical(defaultValueType, typeProvider.nullType))) {
+        if (!(defaultValueType == expectedDefaultValueType ||
+            defaultValueType == typeProvider.nullType)) {
           return false;
         }
       } else {
@@ -148,7 +148,7 @@
     if (arguments[0] is NamedExpression) {
       return false;
     }
-    if (!identical(argumentValues[0].type, typeProvider.stringType)) {
+    if (argumentValues[0].type != typeProvider.stringType) {
       return false;
     }
     String name = argumentValues[0].toStringValue();
@@ -831,7 +831,7 @@
     if (!constructor.isFactory) {
       return null;
     }
-    if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
+    if (constructor.enclosingElement.type == typeProvider.symbolType) {
       // The dart:core.Symbol has a const factory constructor that redirects
       // to dart:_internal.Symbol.  That in turn redirects to an external
       // const constructor, which we won't be able to evaluate.
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index e99b3c5..225fb0a 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -5,7 +5,6 @@
 import 'dart:collection';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -226,9 +225,7 @@
   @override
   void visitClassDeclaration(ClassDeclaration node) {
     bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst;
-    if (resolutionMap
-        .elementDeclaredByClassDeclaration(node)
-        .constructors
+    if (node.declaredElement.constructors
         .any((ConstructorElement e) => e.isConst)) {
       // Instance vars marked "final" need to be included in the dependency
       // graph, since constant constructors implicitly use the values in their
@@ -259,8 +256,7 @@
     super.visitDefaultFormalParameter(node);
     Expression defaultValue = node.defaultValue;
     if (defaultValue != null && node.declaredElement != null) {
-      constantsToCompute
-          .add(resolutionMap.elementDeclaredByFormalParameter(node));
+      constantsToCompute.add(node.declaredElement);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 9d3103e..b6c9ab4 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -992,11 +992,8 @@
         offset = uriLiteral.offset;
         length = uriLiteral.length;
       }
-      ErrorCode errorCode = importElement.isDeferred
-          ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
-          : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
       errors.add(new AnalysisError(libraryElement.source, offset, length,
-          errorCode, [uriLiteral.toSource()]));
+          CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
     }
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 8cf7577..59e5cff 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2786,6 +2786,16 @@
     appendToWithName(buffer, name);
   }
 
+  /// Ensures that dependencies of this constructor, such as default values
+  /// of formal parameters, are evaluated.
+  void computeConstantDependencies() {
+    if (!isConstantEvaluated) {
+      AnalysisOptionsImpl analysisOptions = context.analysisOptions;
+      computeConstants(context.typeProvider, context.typeSystem,
+          context.declaredVariables, [this], analysisOptions.experimentStatus);
+    }
+  }
+
   @deprecated
   @override
   ConstructorDeclaration computeNode() =>
@@ -7526,50 +7536,6 @@
     return getTypeFromParts(className, _definingCompilationUnit, _parts);
   }
 
-  /// Given an update to this library which may have added or deleted edges
-  /// in the import/export graph originating from this node only, remove any
-  /// cached library cycles in the element model which may have been
-  /// invalidated.
-  void invalidateLibraryCycles() {
-    // If we have pre-computed library cycle information, then we must
-    // invalidate the information both on this element, and on certain
-    // other elements.  Edges originating at this node may have been
-    // added or deleted.  A deleted edge that points outside of this cycle
-    // cannot change the cycle information for anything outside of this cycle,
-    // and so it is sufficient to delete the cached library information on this
-    // cycle.  An added edge which points to another node within the cycle
-    // only invalidates the cycle.  An added edge which points to a node earlier
-    // in the topological sort of cycles induces no invalidation (since there
-    // are by definition no back edges from earlier cycles in the topological
-    // order, and hence no possible cycle can have been introduced.  The only
-    // remaining case is that we have added an edge to a node which is later
-    // in the topological sort of cycles.  This can induce cycles, since it
-    // represents a new back edge.  It would be sufficient to invalidate the
-    // cycle information for all nodes that are between the target and the
-    // node in the topological order.  For simplicity, we simply invalidate
-    // all nodes which are reachable from the source node.
-    // Note that in the invalidation phase, we do not cut off when we encounter
-    // a node with no library cycle information, since we do not know whether
-    // we are in the case where invalidation has already been performed, or we
-    // are in the case where library cycles have simply never been computed from
-    // a newly reachable node.
-    Set<LibraryElementImpl> active = new HashSet();
-    void invalidate(LibraryElement element) {
-      LibraryElementImpl library =
-          element is LibraryElementHandle ? element.actualElement : element;
-      if (active.add(library)) {
-        if (library._libraryCycle != null) {
-          library._libraryCycle.forEach(invalidate);
-          library._libraryCycle = null;
-        }
-        library.exportedLibraries.forEach(invalidate);
-        library.importedLibraries.forEach(invalidate);
-      }
-    }
-
-    invalidate(this);
-  }
-
   /// Set whether the library has the given [capability] to
   /// correspond to the given [value].
   void setResolutionCapability(
@@ -8915,6 +8881,9 @@
   bool get isInitializingFormal => false;
 
   @override
+  bool get isLate => false;
+
+  @override
   bool get isPotentiallyMutatedInClosure => true;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index ab33e17..e13d565 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -993,9 +993,6 @@
       super.actualElement as LocalVariableElement;
 
   @override
-  bool get isLate => actualElement.isLate;
-
-  @override
   ElementKind get kind => ElementKind.LOCAL_VARIABLE;
 
   @override
@@ -1181,9 +1178,6 @@
   @override
   bool get isConstantEvaluated => actualElement.isConstantEvaluated;
 
-  @override
-  bool get isLate => actualElement.isLate;
-
   @deprecated
   @override
   DartType get propagatedType => null;
@@ -1277,6 +1271,9 @@
   @override
   bool get isFinal => actualElement.isFinal;
 
+  @override
+  bool get isLate => actualElement.isLate;
+
   @deprecated
   @override
   bool get isPotentiallyMutatedInClosure =>
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index d763f18..fda6a4d 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -297,9 +297,6 @@
   @override
   bool get isEnumConstant => baseElement.isEnumConstant;
 
-  @override
-  bool get isLate => baseElement.isLate;
-
   @deprecated
   @override
   bool get isVirtual => baseElement.isVirtual;
@@ -343,6 +340,16 @@
       Substitution.fromInterfaceType(definingType),
     );
   }
+
+  static FieldElement from2(
+    FieldElement element,
+    MapSubstitution substitution,
+  ) {
+    if (substitution.map.isEmpty) {
+      return element;
+    }
+    return FieldMember(element, substitution);
+  }
 }
 
 /**
@@ -646,6 +653,16 @@
       Substitution.fromInterfaceType(definingType),
     );
   }
+
+  static MethodElement from2(
+    MethodElement element,
+    MapSubstitution substitution,
+  ) {
+    if (substitution.map.isEmpty) {
+      return element;
+    }
+    return MethodMember(element, substitution);
+  }
 }
 
 /**
@@ -1024,6 +1041,9 @@
   bool get isFinal => baseElement.isFinal;
 
   @override
+  bool get isLate => baseElement.isLate;
+
+  @override
   @deprecated
   bool get isPotentiallyMutatedInClosure =>
       baseElement.isPotentiallyMutatedInClosure;
diff --git a/pkg/analyzer/lib/src/dart/element/type_provider.dart b/pkg/analyzer/lib/src/dart/element/type_provider.dart
new file mode 100644
index 0000000..0f4a101
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/element/type_provider.dart
@@ -0,0 +1,298 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+/// Provide common functionality shared by the various TypeProvider
+/// implementations.
+abstract class TypeProviderBase implements TypeProvider {
+  @override
+  List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
+        boolType,
+        doubleType,
+        intType,
+        nullType,
+        numType,
+        stringType
+      ];
+
+  @override
+  bool isObjectGetter(String id) {
+    PropertyAccessorElement element = objectType.element.getGetter(id);
+    return (element != null && !element.isStatic);
+  }
+
+  @override
+  bool isObjectMember(String id) {
+    return isObjectGetter(id) || isObjectMethod(id);
+  }
+
+  @override
+  bool isObjectMethod(String id) {
+    MethodElement element = objectType.element.getMethod(id);
+    return (element != null && !element.isStatic);
+  }
+}
+
+class TypeProviderImpl extends TypeProviderBase {
+  final NullabilitySuffix _nullabilitySuffix;
+  final LibraryElement _coreLibrary;
+  final LibraryElement _asyncLibrary;
+
+  InterfaceType _boolType;
+  InterfaceType _deprecatedType;
+  InterfaceType _doubleType;
+  InterfaceType _functionType;
+  InterfaceType _futureDynamicType;
+  InterfaceType _futureNullType;
+  InterfaceType _futureOrNullType;
+  InterfaceType _futureOrType;
+  InterfaceType _futureType;
+  InterfaceType _intType;
+  InterfaceType _iterableDynamicType;
+  InterfaceType _iterableObjectType;
+  InterfaceType _iterableType;
+  InterfaceType _listType;
+  InterfaceType _mapType;
+  InterfaceType _mapObjectObjectType;
+  DartObjectImpl _nullObject;
+  InterfaceType _nullType;
+  InterfaceType _numType;
+  InterfaceType _objectType;
+  InterfaceType _setType;
+  InterfaceType _stackTraceType;
+  InterfaceType _streamDynamicType;
+  InterfaceType _streamType;
+  InterfaceType _stringType;
+  InterfaceType _symbolType;
+  InterfaceType _typeType;
+
+  /// Initialize a newly created type provider to provide the types defined in
+  /// the given [coreLibrary] and [asyncLibrary].
+  TypeProviderImpl(
+    LibraryElement coreLibrary,
+    LibraryElement asyncLibrary, {
+    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+  })  : _nullabilitySuffix = nullabilitySuffix,
+        _coreLibrary = coreLibrary,
+        _asyncLibrary = asyncLibrary;
+
+  @override
+  InterfaceType get boolType {
+    _boolType ??= _getType(_coreLibrary, "bool");
+    return _boolType;
+  }
+
+  @override
+  DartType get bottomType {
+    if (_nullabilitySuffix == NullabilitySuffix.none) {
+      return BottomTypeImpl.instance;
+    }
+    return BottomTypeImpl.instanceLegacy;
+  }
+
+  @override
+  InterfaceType get deprecatedType {
+    _deprecatedType ??= _getType(_coreLibrary, "Deprecated");
+    return _deprecatedType;
+  }
+
+  @override
+  InterfaceType get doubleType {
+    _doubleType ??= _getType(_coreLibrary, "double");
+    return _doubleType;
+  }
+
+  @override
+  DartType get dynamicType => DynamicTypeImpl.instance;
+
+  @override
+  InterfaceType get functionType {
+    _functionType ??= _getType(_coreLibrary, "Function");
+    return _functionType;
+  }
+
+  @override
+  InterfaceType get futureDynamicType {
+    _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
+    return _futureDynamicType;
+  }
+
+  @override
+  InterfaceType get futureNullType {
+    _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
+    return _futureNullType;
+  }
+
+  @override
+  InterfaceType get futureOrNullType {
+    _futureOrNullType ??= futureOrType.instantiate(<DartType>[nullType]);
+    return _futureOrNullType;
+  }
+
+  @override
+  InterfaceType get futureOrType {
+    _futureOrType ??= _getType(_asyncLibrary, "FutureOr");
+    return _futureOrType;
+  }
+
+  @override
+  InterfaceType get futureType {
+    _futureType ??= _getType(_asyncLibrary, "Future");
+    return _futureType;
+  }
+
+  @override
+  InterfaceType get intType {
+    _intType ??= _getType(_coreLibrary, "int");
+    return _intType;
+  }
+
+  @override
+  InterfaceType get iterableDynamicType {
+    _iterableDynamicType ??= iterableType.instantiate(<DartType>[dynamicType]);
+    return _iterableDynamicType;
+  }
+
+  @override
+  InterfaceType get iterableObjectType {
+    _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
+    return _iterableObjectType;
+  }
+
+  @override
+  InterfaceType get iterableType {
+    _iterableType ??= _getType(_coreLibrary, "Iterable");
+    return _iterableType;
+  }
+
+  @override
+  InterfaceType get listType {
+    _listType ??= _getType(_coreLibrary, "List");
+    return _listType;
+  }
+
+  @override
+  InterfaceType get mapObjectObjectType {
+    return _mapObjectObjectType ??=
+        mapType.instantiate(<DartType>[objectType, objectType]);
+  }
+
+  @override
+  InterfaceType get mapType {
+    _mapType ??= _getType(_coreLibrary, "Map");
+    return _mapType;
+  }
+
+  @override
+  DartType get neverType => BottomTypeImpl.instance;
+
+  @override
+  DartObjectImpl get nullObject {
+    if (_nullObject == null) {
+      _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
+    }
+    return _nullObject;
+  }
+
+  @override
+  InterfaceType get nullType {
+    _nullType ??= _getType(_coreLibrary, "Null");
+    return _nullType;
+  }
+
+  @override
+  InterfaceType get numType {
+    _numType ??= _getType(_coreLibrary, "num");
+    return _numType;
+  }
+
+  @override
+  InterfaceType get objectType {
+    _objectType ??= _getType(_coreLibrary, "Object");
+    return _objectType;
+  }
+
+  @override
+  InterfaceType get setType {
+    return _setType ??= _getType(_coreLibrary, "Set");
+  }
+
+  @override
+  InterfaceType get stackTraceType {
+    _stackTraceType ??= _getType(_coreLibrary, "StackTrace");
+    return _stackTraceType;
+  }
+
+  @override
+  InterfaceType get streamDynamicType {
+    _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
+    return _streamDynamicType;
+  }
+
+  @override
+  InterfaceType get streamType {
+    _streamType ??= _getType(_asyncLibrary, "Stream");
+    return _streamType;
+  }
+
+  @override
+  InterfaceType get stringType {
+    _stringType ??= _getType(_coreLibrary, "String");
+    return _stringType;
+  }
+
+  @override
+  InterfaceType get symbolType {
+    _symbolType ??= _getType(_coreLibrary, "Symbol");
+    return _symbolType;
+  }
+
+  @override
+  InterfaceType get typeType {
+    _typeType ??= _getType(_coreLibrary, "Type");
+    return _typeType;
+  }
+
+  @override
+  VoidType get voidType => VoidTypeImpl.instance;
+
+  TypeProviderImpl withNullability(NullabilitySuffix nullabilitySuffix) {
+    if (_nullabilitySuffix == nullabilitySuffix) {
+      return this;
+    }
+    return TypeProviderImpl(_coreLibrary, _asyncLibrary,
+        nullabilitySuffix: nullabilitySuffix);
+  }
+
+  /// Return the type with the given [name] from the given [library], or
+  /// throw a [StateError] if there is no class with the given name.
+  InterfaceType _getType(LibraryElement library, String name) {
+    var element = library.getType(name);
+    if (element == null) {
+      throw StateError('No definition of type $name');
+    }
+
+    var typeArguments = const <DartType>[];
+    var typeParameters = element.typeParameters;
+    if (typeParameters.isNotEmpty) {
+      typeArguments = typeParameters.map((e) {
+        return TypeParameterTypeImpl(
+          e,
+          nullabilitySuffix: _nullabilitySuffix,
+        );
+      }).toList(growable: false);
+    }
+
+    return InterfaceTypeImpl.explicit(
+      element,
+      typeArguments,
+      nullabilitySuffix: _nullabilitySuffix,
+    );
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index ae53a87..76ba63d 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -3,12 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/error/analyzer_error_code.dart';
 
 /**
  * The hints and coding recommendations for best practices which are not
  * mentioned in the Dart Language Specification.
  */
-class HintCode extends ErrorCode {
+class HintCode extends AnalyzerErrorCode {
   /**
    * When the target expression uses '?.' operator, it can be `null`, so all the
    * subsequent invocations should also use '?.' operator.
@@ -82,7 +83,8 @@
   static const HintCode DEPRECATED_MEMBER_USE = const HintCode(
       'DEPRECATED_MEMBER_USE', "'{0}' is deprecated and shouldn't be used.",
       correction: "Try replacing the use of the deprecated member with the "
-          "replacement.");
+          "replacement.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -112,7 +114,8 @@
       const HintCode('DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE',
           "'{0}' is deprecated and shouldn't be used.",
           correction: "Try replacing the use of the deprecated member with the "
-              "replacement.");
+              "replacement.",
+          hasPublishedDocs: true);
 
   /**
    * Users should not create a class named `Function` anymore.
@@ -308,7 +311,36 @@
   // ```
   static const HintCode INVALID_LITERAL_ANNOTATION = const HintCode(
       'INVALID_LITERAL_ANNOTATION',
-      "Only const constructors can have the `@literal` annotation.");
+      "Only const constructors can have the `@literal` annotation.",
+      hasPublishedDocs: true);
+
+  /**
+   * This hint is generated anywhere where `@required` annotates a named
+   * parameter with a default value.
+   *
+   * Parameters:
+   * 0: the name of the member
+   */
+  static const HintCode INVALID_REQUIRED_NAMED_PARAM = const HintCode(
+      'INVALID_REQUIRED_NAMED_PARAM',
+      "The type parameter '{0}' is annotated with @required but only named "
+          "parameters without a default value can be annotated with it.",
+      correction: "Remove @required.");
+
+  /**
+   * This hint is generated anywhere where `@required` annotates an optional
+   * positional parameter.
+   *
+   * Parameters:
+   * 0: the name of the member
+   */
+  static const HintCode INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM =
+      const HintCode(
+          'INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM',
+          "Incorrect use of the annotation @required on the optional "
+              "positional parameter '{0}'. Optional positional parameters "
+              "cannot be required.",
+          correction: "Remove @required.");
 
   /**
    * This hint is generated anywhere where `@required` annotates a non named
@@ -316,7 +348,12 @@
    *
    * Parameters:
    * 0: the name of the member
+   *
+   * Deprecated: Use the more specific [INVALID_REQUIRED_NAMED_PARAM],
+   * [INVALID_REQUIRED_OPTIONAL_POSITION_PARAM], and
+   * [INVALID_REQUIRED_POSITION_PARAM]
    */
+  @deprecated
   static const HintCode INVALID_REQUIRED_PARAM = const HintCode(
       'INVALID_REQUIRED_PARAM',
       "The type parameter '{0}' is annotated with @required but only named "
@@ -324,6 +361,19 @@
       correction: "Remove @required.");
 
   /**
+   * This hint is generated anywhere where `@required` annotates a non optional
+   * positional parameter.
+   *
+   * Parameters:
+   * 0: the name of the member
+   */
+  static const HintCode INVALID_REQUIRED_POSITIONAL_PARAM = const HintCode(
+      'INVALID_REQUIRED_POSITIONAL_PARAM',
+      "Redundant use of the annotation @required on the required positional "
+          "parameter '{0}'.",
+      correction: "Remove @required.");
+
+  /**
    * This hint is generated anywhere where `@sealed` annotates something other
    * than a class.
    *
@@ -485,7 +535,8 @@
       "This function has a return type of '{0}', but doesn't end with a "
           "return statement.",
       correction: "Try adding a return statement, "
-          "or changing the return type to 'void'.");
+          "or changing the return type to 'void'.",
+      hasPublishedDocs: true);
 
   /**
    * This hint is generated anywhere where a `@sealed` class is used as a
@@ -754,7 +805,8 @@
       'SDK_VERSION_SET_LITERAL',
       "Set literals weren't supported until version 2.2, but this code is "
           "required to be able to run on earlier versions.",
-      correction: "Try updating the SDK constraints.");
+      correction: "Try updating the SDK constraints.",
+      hasPublishedDocs: true);
 
   /**
    * The type Never is being used in code that is expected to run on versions of
@@ -929,7 +981,8 @@
   // If the declaration was intended to be used, then add the missing code.
   static const HintCode UNUSED_ELEMENT = const HintCode(
       'UNUSED_ELEMENT', "The declaration '{0}' isn't referenced.",
-      correction: "Try removing the declaration of '{0}'.");
+      correction: "Try removing the declaration of '{0}'.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -957,7 +1010,8 @@
   // If the field was intended to be used, then add the missing code.
   static const HintCode UNUSED_FIELD = const HintCode(
       'UNUSED_FIELD', "The value of the field '{0}' isn't used.",
-      correction: "Try removing the field, or using it.");
+      correction: "Try removing the field, or using it.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -976,8 +1030,7 @@
   // ```dart
   // import [!'dart:async'!];
   //
-  // void main() {
-  // }
+  // void main() {}
   // ```
   //
   // #### Common fixes
@@ -988,7 +1041,7 @@
   // code.
   static const HintCode UNUSED_IMPORT = const HintCode(
       'UNUSED_IMPORT', "Unused import: '{0}'.",
-      correction: "Try removing the import directive.");
+      correction: "Try removing the import directive.", hasPublishedDocs: true);
 
   /**
    * Unused labels are labels that are never referenced in either a 'break' or
@@ -1026,7 +1079,8 @@
   static const HintCode UNUSED_LOCAL_VARIABLE = const HintCode(
       'UNUSED_LOCAL_VARIABLE',
       "The value of the local variable '{0}' isn't used.",
-      correction: "Try removing the variable, or using it.");
+      correction: "Try removing the variable, or using it.",
+      hasPublishedDocs: true);
 
   /**
    * Unused shown names are names shown on imports which are never used.
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index a5d6149..5ad92c2 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -207,6 +207,15 @@
   static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
       _EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE;
 
+  static const ParserErrorCode EXTENSION_DECLARES_ABSTRACT_MEMBER =
+      _EXTENSION_DECLARES_ABSTRACT_MEMBER;
+
+  static const ParserErrorCode EXTENSION_DECLARES_CONSTRUCTOR =
+      _EXTENSION_DECLARES_CONSTRUCTOR;
+
+  static const ParserErrorCode EXTENSION_DECLARES_INSTANCE_FIELD =
+      _EXTENSION_DECLARES_INSTANCE_FIELD;
+
   static const ParserErrorCode EXTERNAL_AFTER_CONST = _MODIFIER_OUT_OF_ORDER;
 
   static const ParserErrorCode EXTERNAL_AFTER_FACTORY = _MODIFIER_OUT_OF_ORDER;
@@ -530,6 +539,9 @@
       "Can't have both positional and named parameters in a single parameter list.",
       correction: "Try choosing a single style of optional parameters.");
 
+  static const ParserErrorCode MIXIN_DECLARES_CONSTRUCTOR =
+      _MIXIN_DECLARES_CONSTRUCTOR;
+
   static const ParserErrorCode MODIFIER_OUT_OF_ORDER = _MODIFIER_OUT_OF_ORDER;
 
   static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES =
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 ca2f7b9..abde3d8 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -99,6 +99,10 @@
   _VAR_AND_TYPE,
   _INVALID_INITIALIZER,
   _ANNOTATION_WITH_TYPE_ARGUMENTS,
+  _EXTENSION_DECLARES_CONSTRUCTOR,
+  _EXTENSION_DECLARES_INSTANCE_FIELD,
+  _EXTENSION_DECLARES_ABSTRACT_MEMBER,
+  _MIXIN_DECLARES_CONSTRUCTOR,
 ];
 
 const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -244,6 +248,21 @@
         correction:
             "Try moving the export directives before the part directives.");
 
+const ParserErrorCode _EXTENSION_DECLARES_ABSTRACT_MEMBER =
+    const ParserErrorCode('EXTENSION_DECLARES_ABSTRACT_MEMBER',
+        r"Extensions can't declare abstract members.",
+        correction: "Try providing an implementation for the member.");
+
+const ParserErrorCode _EXTENSION_DECLARES_CONSTRUCTOR = const ParserErrorCode(
+    'EXTENSION_DECLARES_CONSTRUCTOR', r"Extensions can't declare constructors.",
+    correction: "Try removing the constructor declaration.");
+
+const ParserErrorCode _EXTENSION_DECLARES_INSTANCE_FIELD =
+    const ParserErrorCode('EXTENSION_DECLARES_INSTANCE_FIELD',
+        r"Extensions can't declare instance fields",
+        correction:
+            "Try removing the field declaration or making it a static field");
+
 const ParserErrorCode _EXTERNAL_CLASS = const ParserErrorCode(
     'EXTERNAL_CLASS', r"Classes can't be declared to be 'external'.",
     correction: "Try removing the keyword 'external'.");
@@ -422,6 +441,9 @@
 const ParserErrorCode _MISSING_STATEMENT =
     const ParserErrorCode('MISSING_STATEMENT', r"Expected a statement.");
 
+const ParserErrorCode _MIXIN_DECLARES_CONSTRUCTOR = const ParserErrorCode(
+    'MIXIN_DECLARES_CONSTRUCTOR', r"Mixins can't declare constructors.");
+
 const ParserErrorCode _MODIFIER_OUT_OF_ORDER = const ParserErrorCode(
     'MODIFIER_OUT_OF_ORDER',
     r"The modifier '#string' should be before the modifier '#string2'.",
diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index 0147fc7..931287a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -31,26 +31,30 @@
   TypeSystem get _typeSystem => _resolver.typeSystem;
 
   /// Return the most specific extension in the current scope for this [type],
-  /// that defines the member with the the [name] and [kind].
+  /// that defines the member with the given [name].
   ///
-  /// If no applicable extensions, return `null`.
+  /// If no applicable extensions, return [ResolutionResult.none].
   ///
-  /// If the match is ambiguous, report an error and return `null`.
+  /// If the match is ambiguous, report an error and return
+  /// [ResolutionResult.ambiguous].
   ResolutionResult findExtension(
-      DartType type, String name, Expression target, ElementKind kind) {
-    var extensions = _getApplicable(type, name, kind);
+    DartType type,
+    String name,
+    Expression target,
+  ) {
+    var extensions = _getApplicable(type, name);
 
     if (extensions.isEmpty) {
       return ResolutionResult.none;
     }
 
     if (extensions.length == 1) {
-      return ResolutionResult(extensions[0].instantiatedMember);
+      return extensions[0].asResolutionResult;
     }
 
     var extension = _chooseMostSpecific(extensions);
     if (extension != null) {
-      return ResolutionResult(extension.instantiatedMember);
+      return extension.asResolutionResult;
     }
 
     _errorReporter.reportErrorForNode(
@@ -58,29 +62,33 @@
       target,
       [
         name,
-        extensions[0].element.name,
-        extensions[1].element.name,
+        extensions[0].extension.name,
+        extensions[1].extension.name,
       ],
     );
     return ResolutionResult.ambiguous;
   }
 
-  /// Return the member with the [name] (without `=`) of the given [kind].
+  /// Return the member with the [name] (without `=`).
   ///
   /// The [node] is fully resolved, and its type arguments are set.
   ExecutableElement getOverrideMember(
-      ExtensionOverride node, String name, ElementKind kind) {
+    ExtensionOverride node,
+    String name, {
+    bool setter = false,
+  }) {
     ExtensionElement element = node.extensionName.staticElement;
 
     ExecutableElement member;
-    if (kind == ElementKind.GETTER) {
-      member = element.getGetter(name);
-    } else if (kind == ElementKind.METHOD) {
-      member = element.getMethod(name);
-    } else if (kind == ElementKind.SETTER) {
+    if (setter) {
       member = element.getSetter(name);
+    } else {
+      member = element.getGetter(name) ?? element.getMethod(name);
     }
-    if (member == null) return null;
+
+    if (member == null) {
+      return null;
+    }
 
     return ExecutableMember.from2(
       member,
@@ -211,27 +219,6 @@
   /// identified.
   _InstantiatedExtension _chooseMostSpecific(
       List<_InstantiatedExtension> extensions) {
-    //
-    // https://github.com/dart-lang/language/blob/master/accepted/future-releases/static-extension-methods/feature-specification.md#extension-conflict-resolution:
-    //
-    // If more than one extension applies to a specific member invocation, then
-    // we resort to a heuristic to choose one of the extensions to apply. If
-    // exactly one of them is "more specific" than all the others, that one is
-    // chosen. Otherwise it is a compile-time error.
-    //
-    // An extension with on type clause T1 is more specific than another
-    // extension with on type clause T2 iff
-    //
-    // 1. T2 is declared in a platform library, and T1 is not, or
-    // 2. they are both declared in platform libraries or both declared in
-    //    non-platform libraries, and
-    // 3. the instantiated type (the type after applying type inference from the
-    //    receiver) of T1 is a subtype of the instantiated type of T2 and either
-    //    not vice versa, or
-    // 4. the instantiate-to-bounds type of T1 is a subtype of the
-    //    instantiate-to-bounds type of T2 and not vice versa.
-    //
-
     for (var i = 0; i < extensions.length; i++) {
       var e1 = extensions[i];
       var isMoreSpecific = true;
@@ -253,9 +240,8 @@
 
   /// Return extensions for the [type] that match the given [name] in the
   /// current scope.
-  List<_InstantiatedExtension> _getApplicable(
-      DartType type, String name, ElementKind kind) {
-    var candidates = _getExtensionsWithMember(name, kind);
+  List<_InstantiatedExtension> _getApplicable(DartType type, String name) {
+    var candidates = _getExtensionsWithMember(name);
 
     var instantiatedExtensions = <_InstantiatedExtension>[];
     for (var candidate in candidates) {
@@ -287,14 +273,7 @@
       }
 
       instantiatedExtensions.add(
-        _InstantiatedExtension(
-          candidate.extension,
-          extendedType,
-          ExecutableMember.from2(
-            candidate.member,
-            substitution,
-          ),
-        ),
+        _InstantiatedExtension(candidate, substitution, extendedType),
       );
     }
 
@@ -302,54 +281,27 @@
   }
 
   /// Return extensions from the current scope, that define a member with the
-  /// given[name].
-  List<_CandidateExtension> _getExtensionsWithMember(
-    String name,
-    ElementKind kind,
-  ) {
+  /// given [name].
+  List<_CandidateExtension> _getExtensionsWithMember(String name) {
     var candidates = <_CandidateExtension>[];
 
-    /// Return `true` if the [elementName] matches the target [name], taking
-    /// into account the `=` on the end of the names of setters.
-    bool matchesName(String elementName) {
-      if (elementName.endsWith('=') && !name.endsWith('=')) {
-        elementName = elementName.substring(0, elementName.length - 1);
-      }
-      return elementName == name;
-    }
-
     /// Add the given [extension] to the list of [candidates] if it defined a
     /// member whose name matches the target [name].
     void checkExtension(ExtensionElement extension) {
-      if (kind == ElementKind.GETTER) {
-        for (var accessor in extension.accessors) {
-          if (accessor.isGetter && matchesName(accessor.name)) {
-            candidates.add(_CandidateExtension(extension, accessor));
-            return;
-          }
+      for (var field in extension.fields) {
+        if (field.name == name) {
+          candidates.add(
+            _CandidateExtension(extension, field: field),
+          );
+          return;
         }
-      } else if (kind == ElementKind.SETTER) {
-        for (var accessor in extension.accessors) {
-          if (accessor.isSetter && matchesName(accessor.name)) {
-            candidates.add(_CandidateExtension(extension, accessor));
-            return;
-          }
-        }
-      } else if (kind == ElementKind.METHOD) {
-        for (var method in extension.methods) {
-          if (matchesName(method.name)) {
-            candidates.add(_CandidateExtension(extension, method));
-            return;
-          }
-        }
-        // Check for a getter that matches a function type.
-        for (var accessor in extension.accessors) {
-          if (accessor.type is FunctionType &&
-              accessor.isGetter &&
-              matchesName(accessor.name)) {
-            candidates.add(_CandidateExtension(extension, accessor));
-            return;
-          }
+      }
+      for (var method in extension.methods) {
+        if (method.name == name) {
+          candidates.add(
+            _CandidateExtension(extension, method: method),
+          );
+          return;
         }
       }
     }
@@ -418,42 +370,39 @@
   /// Return `true` is [e1] is more specific than [e2].
   bool _isMoreSpecific(_InstantiatedExtension e1, _InstantiatedExtension e2) {
     // 1. The latter extension is declared in a platform library, and the
-    // former extension is not.
-    var e1_isInSdk = e1.element.library.isInSdk;
-    var e2_isInSdk = e2.element.library.isInSdk;
+    //    former extension is not.
+    // 2. They are both declared in platform libraries, or both declared in
+    //    non-platform libraries.
+    var e1_isInSdk = e1.extension.library.isInSdk;
+    var e2_isInSdk = e2.extension.library.isInSdk;
     if (e1_isInSdk && !e2_isInSdk) {
       return false;
     } else if (!e1_isInSdk && e2_isInSdk) {
       return true;
     }
 
-    var extendedType1 = e1._extendedType;
-    var extendedType2 = e2._extendedType;
+    var extendedType1 = e1.extendedType;
+    var extendedType2 = e2.extendedType;
 
-    // 2. they are both declared in platform libraries or both declared in
-    //    non-platform libraries, and
-    if (_isSubtypeAndNotViceVersa(extendedType1, extendedType2)) {
-      // 3. the instantiated type (the type after applying type inference from
-      //    the receiver) of T1 is a subtype of the instantiated type of T2 and
-      //    either not vice versa
+    // 3. The instantiated type (the type after applying type inference from
+    //    the receiver) of T1 is a subtype of the instantiated type of T2,
+    //    and either...
+    if (!_isSubtypeOf(extendedType1, extendedType2)) {
+      return false;
+    }
+
+    // 4. ...not vice versa, or...
+    if (!_isSubtypeOf(extendedType2, extendedType1)) {
       return true;
     }
 
+    // 5. ...the instantiate-to-bounds type of T1 is a subtype of the
+    //    instantiate-to-bounds type of T2 and not vice versa.
     // TODO(scheglov) store instantiated types
-    var extendedTypeBound1 = _instantiateToBounds(e1.element);
-    var extendedTypeBound2 = _instantiateToBounds(e2.element);
-    if (_isSubtypeAndNotViceVersa(extendedTypeBound1, extendedTypeBound2)) {
-      // or:
-      // 4. the instantiate-to-bounds type of T1 is a subtype of the
-      //    instantiate-to-bounds type of T2 and not vice versa.
-      return true;
-    }
-
-    return false;
-  }
-
-  bool _isSubtypeAndNotViceVersa(DartType t1, DartType t2) {
-    return _isSubtypeOf(t1, t2) && !_isSubtypeOf(t2, t1);
+    var extendedTypeBound1 = _instantiateToBounds(e1.extension);
+    var extendedTypeBound2 = _instantiateToBounds(e2.extension);
+    return _isSubtypeOf(extendedTypeBound1, extendedTypeBound2) &&
+        !_isSubtypeOf(extendedTypeBound2, extendedTypeBound1);
   }
 
   /// Ask the type system for a subtype check.
@@ -479,19 +428,37 @@
 
 class _CandidateExtension {
   final ExtensionElement extension;
-  final ExecutableElement member;
+  final FieldElement field;
+  final MethodElement method;
 
-  _CandidateExtension(this.extension, this.member);
+  _CandidateExtension(this.extension, {this.field, this.method})
+      : assert(field != null || method != null);
 }
 
 class _InstantiatedExtension {
-  final ExtensionElement element;
-  final DartType _extendedType;
-  final ExecutableElement instantiatedMember;
+  final _CandidateExtension candidate;
+  final MapSubstitution substitution;
+  final DartType extendedType;
 
-  _InstantiatedExtension(
-    this.element,
-    this._extendedType,
-    this.instantiatedMember,
-  );
+  _InstantiatedExtension(this.candidate, this.substitution, this.extendedType);
+
+  ResolutionResult get asResolutionResult {
+    return ResolutionResult(function: method, property: field);
+  }
+
+  ExtensionElement get extension => candidate.extension;
+
+  FieldElement get field {
+    if (candidate.field == null) {
+      return null;
+    }
+    return FieldMember.from2(candidate.field, substitution);
+  }
+
+  MethodElement get method {
+    if (candidate.method == null) {
+      return null;
+    }
+    return MethodMember.from2(candidate.method, substitution);
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 24b4dd6..8fc4935 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -45,8 +44,6 @@
 /// code that are independent from visiting AST during resolution, so can
 /// be extracted.
 class FlowAnalysisHelper {
-  static final _trueLiteral = astFactory.booleanLiteral(null, true);
-
   /// The reused instance for creating new [FlowAnalysis] instances.
   final NodeOperations<Expression> _nodeOperations;
 
@@ -124,6 +121,42 @@
     }
   }
 
+  void breakStatement(BreakStatement node) {
+    var target = getLabelTarget(node, node.label?.staticElement);
+    flow.handleBreak(target);
+  }
+
+  /// Mark the [node] as unreachable if it is not covered by another node that
+  /// is already known to be unreachable.
+  void checkUnreachableNode(AstNode node) {
+    if (flow == null) return;
+    if (flow.isReachable) return;
+
+    if (result != null) {
+      // Ignore the [node] if it is fully covered by the last unreachable.
+      if (result.unreachableNodes.isNotEmpty) {
+        var last = result.unreachableNodes.last;
+        if (node.offset >= last.offset && node.end <= last.end) return;
+      }
+
+      result.unreachableNodes.add(node);
+    }
+  }
+
+  void continueStatement(ContinueStatement node) {
+    var target = getLabelTarget(node, node.label?.staticElement);
+    flow.handleContinue(target);
+  }
+
+  void for_bodyBegin(AstNode node, Expression condition) {
+    flow.for_bodyBegin(node is Statement ? node : null, condition);
+  }
+
+  void for_conditionBegin(AstNode node, Expression condition) {
+    var assigned = assignedVariables.writtenInNode(node);
+    flow.for_conditionBegin(assigned);
+  }
+
   void functionBody_enter(FunctionBody node) {
     _blockFunctionBodyLevel++;
 
@@ -165,47 +198,6 @@
     flow.finish();
   }
 
-  void breakStatement(BreakStatement node) {
-    var target = getLabelTarget(node, node.label?.staticElement);
-    flow.handleBreak(target);
-  }
-
-  /// Mark the [node] as unreachable if it is not covered by another node that
-  /// is already known to be unreachable.
-  void checkUnreachableNode(AstNode node) {
-    if (flow == null) return;
-    if (flow.isReachable) return;
-
-    if (result != null) {
-      // Ignore the [node] if it is fully covered by the last unreachable.
-      if (result.unreachableNodes.isNotEmpty) {
-        var last = result.unreachableNodes.last;
-        if (node.offset >= last.offset && node.end <= last.end) return;
-      }
-
-      result.unreachableNodes.add(node);
-    }
-  }
-
-  void continueStatement(ContinueStatement node) {
-    var target = getLabelTarget(node, node.label?.staticElement);
-    flow.handleContinue(target);
-  }
-
-  void for_bodyBegin(AstNode node, Expression condition) {
-    flow.for_bodyBegin(
-        node is Statement ? node : null, condition ?? _trueLiteral);
-  }
-
-  void for_conditionBegin(AstNode node, Expression condition) {
-    if (condition != null) {
-      var assigned = assignedVariables[node];
-      flow.for_conditionBegin(assigned);
-    } else {
-      flow.booleanLiteral(_trueLiteral, true);
-    }
-  }
-
   void isExpression(IsExpression node) {
     if (flow == null) return;
 
@@ -364,9 +356,9 @@
 
   @override
   void visitDoStatement(DoStatement node) {
-    assignedVariables.beginStatementOrElement();
+    assignedVariables.beginNode();
     super.visitDoStatement(node);
-    assignedVariables.endStatementOrElement(node);
+    assignedVariables.endNode(node);
   }
 
   @override
@@ -386,32 +378,32 @@
 
     expression.accept(this);
 
-    assignedVariables.beginStatementOrElement();
+    assignedVariables.beginNode();
     members.accept(this);
-    assignedVariables.endStatementOrElement(node);
+    assignedVariables.endNode(node);
   }
 
   @override
   void visitTryStatement(TryStatement node) {
-    assignedVariables.beginStatementOrElement();
+    assignedVariables.beginNode();
     node.body.accept(this);
-    assignedVariables.endStatementOrElement(node.body);
+    assignedVariables.endNode(node.body);
 
     node.catchClauses.accept(this);
 
     var finallyBlock = node.finallyBlock;
     if (finallyBlock != null) {
-      assignedVariables.beginStatementOrElement();
+      assignedVariables.beginNode();
       finallyBlock.accept(this);
-      assignedVariables.endStatementOrElement(finallyBlock);
+      assignedVariables.endNode(finallyBlock);
     }
   }
 
   @override
   void visitWhileStatement(WhileStatement node) {
-    assignedVariables.beginStatementOrElement();
+    assignedVariables.beginNode();
     super.visitWhileStatement(node);
-    assignedVariables.endStatementOrElement(node);
+    assignedVariables.endNode(node);
   }
 
   void _handleFor(AstNode node, ForLoopParts forLoopParts, AstNode body) {
@@ -424,19 +416,19 @@
         throw new StateError('Unrecognized for loop parts');
       }
 
-      assignedVariables.beginStatementOrElement();
+      assignedVariables.beginNode();
       forLoopParts.condition?.accept(this);
       body.accept(this);
       forLoopParts.updaters?.accept(this);
-      assignedVariables.endStatementOrElement(node);
+      assignedVariables.endNode(node);
     } else if (forLoopParts is ForEachParts) {
       var iterable = forLoopParts.iterable;
 
       iterable.accept(this);
 
-      assignedVariables.beginStatementOrElement();
+      assignedVariables.beginNode();
       body.accept(this);
-      assignedVariables.endStatementOrElement(node);
+      assignedVariables.endNode(node);
     } else {
       throw new StateError('Unrecognized for loop parts');
     }
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d85976c..39a27a4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -160,11 +160,10 @@
       MethodElement callMethod =
           type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
       if (callMethod != null) {
-        return _resolveArgumentsToFunction(false, argumentList, callMethod);
+        return _resolveArgumentsToFunction(argumentList, callMethod);
       }
     } else if (type is FunctionType) {
-      return _resolveArgumentsToParameters(
-          false, argumentList, type.parameters);
+      return _resolveArgumentsToParameters(argumentList, type.parameters);
     }
     return null;
   }
@@ -283,34 +282,28 @@
   }
 
   /// Given an [argumentList] and the [executableElement] that will be invoked
-  /// using those argument, compute the list of parameters that correspond to the
-  /// list of arguments. An error will be reported if any of the arguments cannot
-  /// be matched to a parameter. The flag [reportAsError] should be `true` if a
-  /// compile-time error should be reported; or `false` if a compile-time warning
-  /// should be reported. Return the parameters that correspond to the arguments,
-  /// or `null` if no correspondence could be computed.
-  List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
+  /// using those argument, compute the list of parameters that correspond to
+  /// the list of arguments. An error will be reported if any of the arguments
+  /// cannot be matched to a parameter. Return the parameters that correspond to
+  /// the arguments, or `null` if no correspondence could be computed.
+  List<ParameterElement> _resolveArgumentsToFunction(
       ArgumentList argumentList, ExecutableElement executableElement) {
     if (executableElement == null) {
       return null;
     }
     List<ParameterElement> parameters = executableElement.parameters;
-    return _resolveArgumentsToParameters(
-        reportAsError, argumentList, parameters);
+    return _resolveArgumentsToParameters(argumentList, parameters);
   }
 
   /// Given an [argumentList] and the [parameters] related to the element that
   /// will be invoked using those arguments, compute the list of parameters that
   /// correspond to the list of arguments. An error will be reported if any of
-  /// the arguments cannot be matched to a parameter. The flag [reportAsError]
-  /// should be `true` if a compile-time error should be reported; or `false` if
-  /// a compile-time warning should be reported. Return the parameters that
+  /// the arguments cannot be matched to a parameter. Return the parameters that
   /// correspond to the arguments.
-  List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
+  List<ParameterElement> _resolveArgumentsToParameters(
       ArgumentList argumentList, List<ParameterElement> parameters) {
     return ResolverVisitor.resolveArgumentsToParameters(
-        argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
-        reportAsError: reportAsError);
+        argumentList, parameters, _resolver.errorReporter.reportErrorForNode);
   }
 
   /// Given that we are accessing a property of the given [classElement] with the
@@ -349,7 +342,6 @@
       receiverType,
       name,
       nameNode,
-      ElementKind.METHOD,
     );
 
     if (!result.isSingle) {
@@ -357,7 +349,7 @@
       return result;
     }
 
-    ExecutableElement member = result.element;
+    ExecutableElement member = result.getter;
     nameNode.staticElement = member;
 
     if (member.isStatic) {
@@ -399,10 +391,7 @@
 
   void _resolveExtensionOverride(MethodInvocation node,
       ExtensionOverride override, SimpleIdentifier nameNode, String name) {
-    var member = _extensionResolver.getOverrideMember(
-            override, name, ElementKind.METHOD) ??
-        _extensionResolver.getOverrideMember(
-            override, name, ElementKind.GETTER);
+    var member = _extensionResolver.getOverrideMember(override, name);
 
     if (member == null) {
       _setDynamicResolution(node);
@@ -446,11 +435,11 @@
       return;
     }
 
-    ResolutionResult result = _extensionResolver.findExtension(
-        receiverType, name, nameNode, ElementKind.METHOD);
+    ResolutionResult result =
+        _extensionResolver.findExtension(receiverType, name, nameNode);
     if (result.isSingle) {
-      nameNode.staticElement = result.element;
-      var calleeType = _getCalleeType(node, result.element);
+      nameNode.staticElement = result.getter;
+      var calleeType = _getCalleeType(node, result.getter);
       return _setResolution(node, calleeType);
     } else if (result.isAmbiguous) {
       return;
@@ -585,10 +574,9 @@
       return;
     }
 
-    var result = _extensionResolver.findExtension(
-        receiverType, name, nameNode, ElementKind.METHOD);
+    var result = _extensionResolver.findExtension(receiverType, name, nameNode);
     if (result.isSingle) {
-      var target = result.element;
+      var target = result.getter;
       if (target != null) {
         nameNode.staticElement = target;
         var calleeType = _getCalleeType(node, target);
@@ -751,9 +739,9 @@
       var call = _inheritance.getMember(type, _nameCall);
       if (call == null) {
         var result = _extensionResolver.findExtension(
-            type, _nameCall.name, node.methodName, ElementKind.METHOD);
+            type, _nameCall.name, node.methodName);
         if (result.isSingle) {
-          call = result.element;
+          call = result.function;
         } else if (result.isAmbiguous) {
           return;
         }
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
index 1d91bf8..d3b7288 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
@@ -17,18 +17,27 @@
   /// The state of the result.
   final _ResolutionResultState state;
 
-  /// The element that was found, or `null` if the [state] is not
-  /// [_ResolutionResultState.single].
-  final ExecutableElement element;
+  /// The function that was found, or `null` if the [state] is not
+  /// [_ResolutionResultState.single], or a [property] was found.
+  final ExecutableElement function;
+
+  /// The property that was found, or `null` if the [state] is not
+  /// [_ResolutionResultState.single], or a [function] was found.
+  final PropertyInducingElement property;
 
   /// Initialize a newly created result to represent resolving to a single
-  /// [element].
-  ResolutionResult(this.element)
-      : assert(element != null),
+  /// [function] or [property].
+  ResolutionResult({this.function, this.property})
+      : assert(function != null || property != null),
         state = _ResolutionResultState.single;
 
   /// Initialize a newly created result with no element and the given [state].
-  const ResolutionResult._(this.state) : element = null;
+  const ResolutionResult._(this.state)
+      : function = null,
+        property = null;
+
+  /// Return the getter of the [property], or the [function].
+  ExecutableElement get getter => function ?? property?.getter;
 
   /// Return `true` if this result represents the case where multiple ambiguous
   /// elements were found.
@@ -41,6 +50,17 @@
   /// Return `true` if this result represents the case where a single element
   /// was found.
   bool get isSingle => state == _ResolutionResultState.single;
+
+  /// If this is a property, return `true` is the property is static.
+  /// If this is a function, return `true` is the function is static.
+  /// Otherwise return `false`.
+  bool get isStatic {
+    return function?.isStatic ?? property?.isStatic ?? false;
+  }
+
+  /// Return the setter of the [property], or `null` if this is not a property,
+  /// or the property does not have a setter.
+  ExecutableElement get setter => property?.setter;
 }
 
 /// The state of a [ResolutionResult].
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 655059b..ef8de3a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -407,12 +407,14 @@
   List<ExtensionElement> get extensions {
     if (_extensions == null) {
       _extensions = [];
-      for (var namespace in _importedNamespaces) {
-        for (var element in namespace.definedNames.values) {
-          if (element is ExtensionElement &&
-              element.name.isNotEmpty /* named */ &&
-              !_extensions.contains(element)) {
-            _extensions.add(element);
+      List<ImportElement> imports = _definingLibrary.imports;
+      int count = imports.length;
+      for (int i = 0; i < count; i++) {
+        if (imports[i].prefix == null) {
+          for (var element in imports[i].namespace.definedNames.values) {
+            if (element is ExtensionElement && !_extensions.contains(element)) {
+              _extensions.add(element);
+            }
           }
         }
       }
@@ -807,7 +809,7 @@
    */
   void _addIfPublic(Map<String, Element> definedNames, Element element) {
     String name = element.name;
-    if (name != null && !Scope.isPrivateName(name)) {
+    if (name != null && name.isNotEmpty && !Scope.isPrivateName(name)) {
       definedNames[name] = element;
     }
   }
@@ -890,9 +892,9 @@
         }
       }
       _addAllFromNamespace(
-          definedNames,
-          (library.context as InternalAnalysisContext)
-              .getPublicNamespace(library));
+        definedNames,
+        createPublicNamespaceForLibrary(library),
+      );
       return definedNames;
     } finally {
       visitedElements.remove(library);
diff --git a/pkg/analyzer/lib/src/error/analyzer_error_code.dart b/pkg/analyzer/lib/src/error/analyzer_error_code.dart
new file mode 100644
index 0000000..29bcc8c
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/analyzer_error_code.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.
+
+import 'package:analyzer/error/error.dart';
+
+/// A superclass for error codes that can have a url associated with them.
+abstract class AnalyzerErrorCode extends ErrorCode {
+  /// Initialize a newly created error code.
+  const AnalyzerErrorCode.temporary(String name, String message,
+      {String correction, bool hasPublishedDocs, bool isUnresolvedIdentifier})
+      : super.temporary(name, message,
+            correction: correction,
+            hasPublishedDocs: hasPublishedDocs ?? false,
+            isUnresolvedIdentifier: isUnresolvedIdentifier ?? false);
+
+  String get url {
+    if (hasPublishedDocs) {
+      return 'https://dart.dev/tools/diagnostic-messages#${name.toLowerCase()}';
+    }
+    return null;
+  }
+}
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index fe637f4..49aa71d 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -5,6 +5,8 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 
+import 'analyzer_error_code.dart';
+
 export 'package:analyzer/src/analysis_options/error/option_codes.dart';
 export 'package:analyzer/src/dart/error/hint_codes.dart';
 export 'package:analyzer/src/dart/error/lint_codes.dart';
@@ -18,7 +20,7 @@
  * treat these errors differently depending whether it is compiling it "checked"
  * mode).
  */
-class CheckedModeCompileTimeErrorCode extends ErrorCode {
+class CheckedModeCompileTimeErrorCode extends AnalyzerErrorCode {
   // TODO(paulberry): improve the text of these error messages so that it's
   // clear to the user that the error is coming from constant evaluation (and
   // hence the constant needs to be a subtype of the annotated type) as opposed
@@ -102,7 +104,7 @@
  * error to be generated and for the error message to explain what is wrong and,
  * when appropriate, how the problem can be corrected.
  */
-class CompileTimeErrorCode extends ErrorCode {
+class CompileTimeErrorCode extends AnalyzerErrorCode {
   /**
    * Member lookups ignore abstract declarations, which means that there will
    * be a compile-time error if the targeted member `m` is abstract, as well as
@@ -219,7 +221,8 @@
               "a map or a set.",
           correction:
               "Try removing or changing some of the elements so that all of "
-              "the elements are consistent.");
+              "the elements are consistent.",
+          hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -299,7 +302,8 @@
               "have enough information for type inference to work.",
           correction:
               "Try adding type arguments to the literal (one for sets, two "
-              "for maps).");
+              "for maps).",
+          hasPublishedDocs: true);
 
   /**
    * 15 Metadata: The constant expression given in an annotation is type checked
@@ -350,6 +354,18 @@
               "Try marking the function body with either 'async' or 'async*'.");
 
   /**
+   * It is a compile-time error if a built-in identifier is used as the declared
+   * name of an extension.
+   *
+   * Parameters:
+   * 0: the built-in identifier that is being used
+   */
+  static const CompileTimeErrorCode BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME =
+      const CompileTimeErrorCode('BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME',
+          "The built-in identifier '{0}' can't be used as an extension name.",
+          correction: "Try choosing a different name for the extension.");
+
+  /**
    * 16.33 Identifier Reference: It is a compile-time error if a built-in
    * identifier is used as the declared name of a prefix, class, type parameter
    * or type alias.
@@ -693,7 +709,8 @@
       const CompileTimeErrorCode('CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE',
           "Const variables must be initialized with a constant value.",
           correction:
-              "Try changing the initializer to be a constant expression.");
+              "Try changing the initializer to be a constant expression.",
+          hasPublishedDocs: true);
 
   /**
    * 5 Variables: A constant variable must be initialized to a compile-time
@@ -1131,7 +1148,9 @@
   // ```
   static const CompileTimeErrorCode EQUAL_KEYS_IN_CONST_MAP =
       const CompileTimeErrorCode('EQUAL_KEYS_IN_CONST_MAP',
-          "Two keys in a constant map literal can't be equal.");
+          "Two keys in a constant map literal can't be equal.",
+          correction: "Change or remove the duplicate key.",
+          hasPublishedDocs: true);
 
   /**
    * 16.11 Sets: It is a compile-time error if two elements of a constant set
@@ -1193,7 +1212,8 @@
           'EXPRESSION_IN_MAP', "Expressions can't be used in a map literal.",
           correction:
               "Try removing the expression or converting it to be a map "
-              "entry.");
+              "entry.",
+          hasPublishedDocs: true);
 
   /**
    * 7.9 Superclasses: It is a compile-time error if the extends clause of a
@@ -1260,6 +1280,15 @@
               "removing the extends clause.");
 
   /**
+   * Parameters:
+   * 0: the name of the extension
+   */
+  static const CompileTimeErrorCode EXTENSION_AS_EXPRESSION =
+      const CompileTimeErrorCode('EXTENSION_AS_EXPRESSION',
+          "Extension '{0}' can't be used as an expression.",
+          correction: "Try replacing it with a valid expression.");
+
+  /**
    * It is for an extension to define a static member and an instance member
    * with the same base name.
    *
@@ -1278,32 +1307,6 @@
   /**
    * No parameters.
    */
-  static const CompileTimeErrorCode EXTENSION_DECLARES_ABSTRACT_MEMBER =
-      const CompileTimeErrorCode('EXTENSION_DECLARES_ABSTRACT_MEMBER',
-          "Extensions can't declare abstract members.",
-          correction: "Try providing an implementation for the member.");
-
-  /**
-   * No parameters.
-   */
-  static const CompileTimeErrorCode EXTENSION_DECLARES_CONSTRUCTOR =
-      const CompileTimeErrorCode('EXTENSION_DECLARES_CONSTRUCTOR',
-          "Extensions can't declare constructors.",
-          correction: "Try removing the constructor declaration.");
-
-  /**
-   * No parameters.
-   */
-  static const CompileTimeErrorCode EXTENSION_DECLARES_INSTANCE_FIELD =
-      const CompileTimeErrorCode('EXTENSION_DECLARES_INSTANCE_FIELD',
-          "Extensions can't declare instance fields.",
-          correction:
-              "Try removing the field declaration or making it a static "
-              "field.");
-
-  /**
-   * No parameters.
-   */
   static const CompileTimeErrorCode EXTENSION_DECLARES_MEMBER_OF_OBJECT =
       const CompileTimeErrorCode(
           'EXTENSION_DECLARES_MEMBER_OF_OBJECT',
@@ -1586,8 +1589,6 @@
    *
    * Parameters:
    * 0: the uri pointing to a non-library declaration
-   *
-   * See [StaticWarningCode.IMPORT_OF_NON_LIBRARY].
    */
   static const CompileTimeErrorCode IMPORT_OF_NON_LIBRARY =
       const CompileTimeErrorCode('IMPORT_OF_NON_LIBRARY',
@@ -2503,8 +2504,8 @@
   //
   // The analyzer produces this diagnostic when an element in a constant list
   // literal isn't a constant value. The list literal can be constant either
-  // explicitly (because it's prefixed by the keyword `const`) or implicitly
-  // (because it appears in a <a href=”#constant-context”>constant context</a>).
+  // explicitly (because it's prefixed by the `const` keyword) or implicitly
+  // (because it appears in a [constant context](#constant-context)).
   //
   // #### Example
   //
@@ -2519,8 +2520,8 @@
   // #### Common fixes
   //
   // If the list needs to be a constant list, then convert the element to be a
-  // constant. In the example above, you might add the keyword `const`
-  // to the declaration of `x`:
+  // constant. In the example above, you might add the `const` keyword to the
+  // declaration of `x`:
   //
   // ```dart
   // const int x = 2;
@@ -2539,8 +2540,8 @@
   static const CompileTimeErrorCode NON_CONSTANT_LIST_ELEMENT =
       const CompileTimeErrorCode('NON_CONSTANT_LIST_ELEMENT',
           "The values in a const list literal must be constants.",
-          correction:
-              "Try removing the keyword 'const' from the list literal.");
+          correction: "Try removing the keyword 'const' from the list literal.",
+          hasPublishedDocs: true);
 
   /**
    * 12.6 Lists: It is a compile time error if an element of a constant list
@@ -2674,6 +2675,10 @@
           "{0} positional argument(s) expected, but {1} found.",
           correction: "Try adding the missing arguments.");
 
+  @Deprecated('Use CompileTimeErrorCode NOT_ENOUGH_POSITIONAL_ARGUMENTS')
+  static const CompileTimeErrorCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
+      NOT_ENOUGH_POSITIONAL_ARGUMENTS;
+
   /**
    * It is an error if an instance field with potentially non-nullable type has
    * no initializer expression and is not initialized in a constructor via an
@@ -2752,7 +2757,8 @@
   // ```
   static const CompileTimeErrorCode NOT_ITERABLE_SPREAD =
       const CompileTimeErrorCode('NOT_ITERABLE_SPREAD',
-          "Spread elements in list or set literals must implement 'Iterable'.");
+          "Spread elements in list or set literals must implement 'Iterable'.",
+          hasPublishedDocs: true);
 
   static const CompileTimeErrorCode NOT_MAP_SPREAD = const CompileTimeErrorCode(
       'NOT_MAP_SPREAD',
@@ -3073,6 +3079,7 @@
   //
   // ```dart
   // C f() {}
+  //
   // class C {
   //   factory C() = [!f!];
   // }
@@ -3091,6 +3098,7 @@
   //
   // ```dart
   // C f() {}
+  //
   // class C {
   //   factory C() => f();
   // }
@@ -3100,7 +3108,8 @@
           'REDIRECT_TO_NON_CLASS',
           "The name '{0}' isn't a type and can't be used in a redirected "
               "constructor.",
-          correction: "Try redirecting to a different constructor.");
+          correction: "Try redirecting to a different constructor.",
+          hasPublishedDocs: true);
 
   /**
    * 7.6.2 Factories: It is a compile-time error if <i>k</i> is prefixed with
@@ -3263,6 +3272,7 @@
   //
   // ```dart
   // class A<E extends num> {}
+  //
   // var a = A<[!String!]>();
   // ```
   //
@@ -3272,12 +3282,14 @@
   //
   // ```dart
   // class A<E extends num> {}
+  //
   // var a = A<int>();
   // ```
   static const CompileTimeErrorCode TYPE_ARGUMENT_NOT_MATCHING_BOUNDS =
       const CompileTimeErrorCode(
           'TYPE_ARGUMENT_NOT_MATCHING_BOUNDS', "'{0}' doesn't extend '{1}'.",
-          correction: "Try using a type that is or is a subclass of '{1}'.");
+          correction: "Try using a type that is or is a subclass of '{1}'.",
+          hasPublishedDocs: true);
 
   /**
    * It is a compile-time error if a generic function type is used as a bound
@@ -3336,12 +3348,50 @@
           isUnresolvedIdentifier: true);
 
   /**
-   * 16.12.2 Const: It is a compile-time error if <i>T</i> is not a class
-   * accessible in the current scope, optionally followed by type arguments.
+   * Parameters:
+   * 0: the name of the undefined class
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when it encounters an identifier that
+  // appears to be the name of a class but either isn't defined or isn't visible
+  // in the scope in which it's being referenced.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // class Point {}
+  //
+  // void main() {
+  //   [!Piont!] p;
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the identifier isn't defined, then either define it or replace it with
+  // the name of a class that is defined. The example above can be corrected by
+  // fixing the spelling of the class:
+  //
+  // ```dart
+  // class Point {}
+  //
+  // void main() {
+  //   Point p;
+  // }
+  // ```
+  //
+  // If the class is defined but isn't visible, then you probably need to add an
+  // import.
   static const CompileTimeErrorCode UNDEFINED_CLASS =
       const CompileTimeErrorCode('UNDEFINED_CLASS', "Undefined class '{0}'.",
-          correction: "Try defining the class.", isUnresolvedIdentifier: true);
+          correction:
+              "Try changing the name to the name of an existing class, or "
+              "creating a class with the name '{0}'.",
+          hasPublishedDocs: true,
+          isUnresolvedIdentifier: true);
 
   /**
    * 7.6.1 Generative Constructors: Let <i>C</i> be the class in which the
@@ -3414,23 +3464,79 @@
               "defining a setter named '{0}'.");
 
   /**
-   * 12.14.2 Binding Actuals to Formals: Furthermore, each <i>q<sub>i</sub></i>,
-   * <i>1<=i<=l</i>, must have a corresponding named parameter in the set
-   * {<i>p<sub>n+1</sub></i> ... <i>p<sub>n+k</sub></i>} or a static warning
-   * occurs.
-   *
-   * 16.12.2 Const: It is a compile-time error if evaluation of a constant
-   * object results in an uncaught exception being thrown.
-   *
    * Parameters:
    * 0: the name of the requested named parameter
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a method or function invocation
+  // has a named argument, but the method or function being invoked doesn’t
+  // define a parameter with the same name.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // class C {
+  //   m({int b}) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.m([!a!]: 1);
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the argument name is mistyped, then replace it with the correct name.
+  // The example above can be fixed by changing `a` to `b`:
+  //
+  // ```dart
+  // class C {
+  //   m({int b}) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.m(b: 1);
+  // }
+  // ```
+  //
+  // If a subclass adds a parameter with the name in question, then cast the
+  // target to the subclass:
+  //
+  // ```dart
+  // class C {
+  //   m({int b}) {}
+  // }
+  //
+  // class D extends C {
+  //   m({int a, int b}) {}
+  // }
+  //
+  // void f(C c) {
+  //   (c as D).m(a: 1);
+  // }
+  // ```
+  //
+  // If the parameter should be added to the function, then add it:
+  //
+  // ```dart
+  // class C {
+  //   m({int a, int b}) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.m(a: 1);
+  // }
+  // ```
   static const CompileTimeErrorCode UNDEFINED_NAMED_PARAMETER =
       const CompileTimeErrorCode('UNDEFINED_NAMED_PARAMETER',
           "The named parameter '{0}' isn't defined.",
           correction:
               "Try correcting the name to an existing named parameter's name, "
-              "or defining a named parameter with the name '{0}'.");
+              "or defining a named parameter with the name '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -3459,7 +3565,8 @@
       const CompileTimeErrorCode(
           'URI_DOES_NOT_EXIST', "Target of URI doesn't exist: '{0}'.",
           correction: "Try creating the file referenced by the URI, or "
-              "Try using a URI for a file that does exist.");
+              "Try using a URI for a file that does exist.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -3498,7 +3605,8 @@
       const CompileTimeErrorCode('URI_HAS_NOT_BEEN_GENERATED',
           "Target of URI hasn't been generated: '{0}'.",
           correction: "Try running the generator that will generate the file "
-              "referenced by the URI.");
+              "referenced by the URI.",
+          hasPublishedDocs: true);
 
   /**
    * 14.1 Imports: It is a compile-time error if <i>x</i> is not a compile-time
@@ -3622,7 +3730,7 @@
  * error to be generated and for the error message to explain what is wrong and,
  * when appropriate, how the problem can be corrected.
  */
-class StaticTypeWarningCode extends ErrorCode {
+class StaticTypeWarningCode extends AnalyzerErrorCode {
   /**
    * 12.7 Lists: A fresh instance (7.6.1) <i>a</i>, of size <i>n</i>, whose
    * class implements the built-in class <i>List&lt;E></i> is allocated.
@@ -3755,6 +3863,7 @@
   //
   // ```dart
   // typedef Binary = int Function(int, int);
+  //
   // int f() {
   //   return [!Binary!](1, 2);
   // }
@@ -3770,7 +3879,8 @@
           // better error and correction messages.
           correction:
               "Try correcting the name to match an existing function, or "
-              "define a method or function named '{0}'.");
+              "define a method or function named '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * 12.14.4 Function Expression Invocation: A function expression invocation
@@ -3870,6 +3980,7 @@
           "The name '{0}' isn't a type so it can't be used as a type argument.",
           correction: "Try correcting the name to an existing type, or "
               "defining a type named '{0}'.",
+          hasPublishedDocs: true,
           isUnresolvedIdentifier: true);
 
   /**
@@ -3950,6 +4061,7 @@
   //
   // ```dart
   // List<int> empty() => [];
+  //
   // void main() {
   //   print([!emty!]());
   // }
@@ -3963,6 +4075,7 @@
   //
   // ```dart
   // List<int> empty() => [];
+  //
   // void main() {
   //   print(empty());
   // }
@@ -3976,6 +4089,7 @@
           correction: "Try importing the library that defines '{0}', "
               "correcting the name to the name of an existing function, or "
               "defining a function named '{0}'.",
+          hasPublishedDocs: true,
           isUnresolvedIdentifier: true);
 
   /**
@@ -3994,12 +4108,7 @@
   // The following code produces this diagnostic:
   //
   // ```dart
-  // class Point {
-  //   final int x;
-  //   final int y;
-  //   Point(this.x, this.y);
-  //   operator +(Point other) => Point(x + other.x, y + other.[!z!]);
-  // }
+  // int f(String s) => s.[!len!];
   // ```
   //
   // #### Common fix
@@ -4009,12 +4118,7 @@
   // fixing the spelling of the getter:
   //
   // ```dart
-  // class Point {
-  //   final int x;
-  //   final int y;
-  //   Point(this.x, this.y);
-  //   operator +(Point other) => Point(x + other.x, y + other.y);
-  // }
+  // int f(String s) => s.length;
   // ```
   static const StaticTypeWarningCode UNDEFINED_GETTER =
       // TODO(brianwilkerson) When the "target" is an enum, report
@@ -4023,7 +4127,8 @@
           "The getter '{0}' isn't defined for the class '{1}'.",
           correction: "Try importing the library that defines '{0}', "
               "correcting the name to the name of an existing getter, or "
-              "defining a getter or field named '{0}'.");
+              "defining a getter or field named '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -4058,7 +4163,8 @@
           "The method '{0}' isn't defined for the class '{1}'.",
           correction:
               "Try correcting the name to the name of an existing method, or "
-              "defining a method named '{0}'.");
+              "defining a method named '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * 12.18 Assignment: Evaluation of an assignment of the form
@@ -4143,7 +4249,8 @@
           "The setter '{0}' isn't defined for the class '{1}'.",
           correction: "Try importing the library that defines '{0}', "
               "correcting the name to the name of an existing setter, or "
-              "defining a setter or field named '{0}'.");
+              "defining a setter or field named '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * 12.17 Getter Invocation: Let <i>T</i> be the static type of <i>e</i>. It is
@@ -4367,7 +4474,7 @@
  * to be generated and for the error message to explain what is wrong and, when
  * appropriate, how the problem can be corrected.
  */
-class StaticWarningCode extends ErrorCode {
+class StaticWarningCode extends AnalyzerErrorCode {
   /**
    * 14.1 Imports: If a name <i>N</i> is referenced by a library <i>L</i> and
    * <i>N</i> is introduced into the top level scope <i>L</i> by more than one
@@ -4444,7 +4551,8 @@
       const StaticWarningCode(
           'ARGUMENT_TYPE_NOT_ASSIGNABLE',
           "The argument type '{0}' can't be assigned to the parameter type "
-              "'{1}'.");
+              "'{1}'.",
+          hasPublishedDocs: true);
 
   /**
    * 5 Variables: Attempting to assign to a final variable elsewhere will cause
@@ -4582,32 +4690,14 @@
           correction:
               "Try adding a hide clause to one of the export directives.");
 
-  /**
-   * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m &lt;
-   * h</i> or if <i>m &gt; n</i>.
-   *
-   * Parameters:
-   * 0: the maximum number of positional arguments
-   * 1: the actual number of positional arguments given
-   */
-  static const StaticWarningCode EXTRA_POSITIONAL_ARGUMENTS =
-      const StaticWarningCode('EXTRA_POSITIONAL_ARGUMENTS',
-          "Too many positional arguments: {0} expected, but {1} found.",
-          correction: "Try removing the extra positional arguments.");
+  @Deprecated('Use CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS')
+  static const CompileTimeErrorCode EXTRA_POSITIONAL_ARGUMENTS =
+      CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS;
 
-  /**
-   * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m &lt;
-   * h</i> or if <i>m &gt; n</i>.
-   *
-   * Parameters:
-   * 0: the maximum number of positional arguments
-   * 1: the actual number of positional arguments given
-   */
-  static const StaticWarningCode EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED =
-      const StaticWarningCode('EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED',
-          "Too many positional arguments: {0} expected, but {1} found.",
-          correction: "Try removing the extra positional arguments, "
-              "or specifying the name for named arguments.");
+  @Deprecated(
+      'Use CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED')
+  static const CompileTimeErrorCode EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED =
+      CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED;
 
   /**
    * 5. Variables: It is a static warning if a final instance variable that has
@@ -4764,19 +4854,9 @@
               "'{2}'.",
           correction: "Try adding a hide clause to one of the imports.");
 
-  /**
-   * 14.1 Imports: It is a static warning if the specified URI of a deferred
-   * import does not refer to a library declaration.
-   *
-   * Parameters:
-   * 0: the uri pointing to a non-library declaration
-   *
-   * See [CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY].
-   */
-  static const StaticWarningCode IMPORT_OF_NON_LIBRARY =
-      const StaticWarningCode('IMPORT_OF_NON_LIBRARY',
-          "The imported library '{0}' can't have a part-of directive.",
-          correction: "Try importing the library that the part is a part of.");
+  @Deprecated('Use CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY')
+  static const CompileTimeErrorCode IMPORT_OF_NON_LIBRARY =
+      CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
 
   /**
    * 7.1 Instance Methods: It is a static warning if an instance method
@@ -5194,20 +5274,12 @@
   // Replace the name with the name of a type.
   static const StaticWarningCode NOT_A_TYPE = const StaticWarningCode(
       'NOT_A_TYPE', "{0} isn't a type.",
-      correction: "Try correcting the name to match an existing type.");
+      correction: "Try correcting the name to match an existing type.",
+      hasPublishedDocs: true);
 
-  /**
-   * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m &lt;
-   * h</i> or if <i>m &gt; n</i>.
-   *
-   * Parameters:
-   * 0: the expected number of required arguments
-   * 1: the actual number of positional arguments given
-   */
-  static const StaticWarningCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
-      const StaticWarningCode('NOT_ENOUGH_REQUIRED_ARGUMENTS',
-          "{0} required argument(s) expected, but {1} found.",
-          correction: "Try adding the additional required arguments.");
+  @Deprecated('Use CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS')
+  static const CompileTimeErrorCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
+      CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS;
 
   /**
    * 14.3 Parts: It is a static warning if the referenced part declaration
@@ -5258,31 +5330,13 @@
               "invoking the desired constructor rather than redirecting to "
               "it.");
 
-  /**
-   * 7.6.2 Factories: It is a static warning if type does not denote a class
-   * accessible in the current scope; if type does denote such a class <i>C</i>
-   * it is a static warning if the referenced constructor (be it <i>type</i> or
-   * <i>type.id</i>) is not a constructor of <i>C</i>.
-   */
-  static const StaticWarningCode REDIRECT_TO_MISSING_CONSTRUCTOR =
-      const StaticWarningCode('REDIRECT_TO_MISSING_CONSTRUCTOR',
-          "The constructor '{0}' couldn't be found in '{1}'.",
-          correction:
-              "Try correcting the constructor name to an existing constructor, "
-              "or defining the constructor in '{1}'.");
+  @Deprecated('Use CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR')
+  static const CompileTimeErrorCode REDIRECT_TO_MISSING_CONSTRUCTOR =
+      CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR;
 
-  /**
-   * 7.6.2 Factories: It is a static warning if type does not denote a class
-   * accessible in the current scope; if type does denote such a class <i>C</i>
-   * it is a static warning if the referenced constructor (be it <i>type</i> or
-   * <i>type.id</i>) is not a constructor of <i>C</i>.
-   */
-  static const StaticWarningCode REDIRECT_TO_NON_CLASS =
-      const StaticWarningCode(
-          'REDIRECT_TO_NON_CLASS',
-          "The name '{0}' isn't a type and can't be used in a redirected "
-              "constructor.",
-          correction: "Try correcting the name to match an existing class.");
+  @Deprecated('Use CompileTimeErrorCode.REDIRECT_TO_NON_CLASS')
+  static const CompileTimeErrorCode REDIRECT_TO_NON_CLASS =
+      CompileTimeErrorCode.REDIRECT_TO_NON_CLASS;
 
   /**
    * 13.12 Return: Let <i>f</i> be the function immediately enclosing a return
@@ -5378,50 +5432,13 @@
           correction: "Try removing the reference to the type parameter, or "
               "making the member an instance member.");
 
-  /**
-   * Parameters:
-   * 0: the name of the undefined class
-   */
-  // #### Description
-  //
-  // The analyzer produces this diagnostic when it encounters an identifier that
-  // appears to be the name of a class but either isn't defined or isn't visible
-  // in the scope in which it's being referenced.
-  //
-  // #### Example
-  //
-  // The following code produces this diagnostic:
-  //
-  // ```dart
-  // class Point {}
-  // void main() {
-  //   [!Piont!] p;
-  // }
-  // ```
-  //
-  // #### Common fixes
-  //
-  // If the identifier isn't defined, then either define it or replace it with
-  // the name of a class that is defined. The example above can be corrected by
-  // fixing the spelling of the class:
-  //
-  // ```dart
-  // class Point {}
-  // void main() {
-  //   Point p;
-  // }
-  // ```
-  //
-  // If the class is defined but isn't visible, then you probably need to add an
-  // import.
-  static const StaticWarningCode UNDEFINED_CLASS = const StaticWarningCode(
-      'UNDEFINED_CLASS', "Undefined class '{0}'.",
-      correction: "Try changing the name to the name of an existing class, or "
-          "creating a class with the name '{0}'.",
-      isUnresolvedIdentifier: true);
+  @Deprecated('Use CompileTimeErrorCode.UNDEFINED_CLASS')
+  static const CompileTimeErrorCode UNDEFINED_CLASS =
+      CompileTimeErrorCode.UNDEFINED_CLASS;
 
   /**
-   * Same as [UNDEFINED_CLASS], but to catch using "boolean" instead of "bool".
+   * Same as [CompileTimeErrorCode.UNDEFINED_CLASS], but to catch using
+   * "boolean" instead of "bool".
    */
   static const StaticWarningCode UNDEFINED_CLASS_BOOLEAN =
       const StaticWarningCode(
@@ -5462,6 +5479,7 @@
       const StaticWarningCode('UNDEFINED_IDENTIFIER', "Undefined name '{0}'.",
           correction: "Try correcting the name to one that is defined, or "
               "defining the name.",
+          hasPublishedDocs: true,
           isUnresolvedIdentifier: true);
 
   /**
@@ -5474,74 +5492,9 @@
               "defining the name, or "
               "adding 'async' to the enclosing function body.");
 
-  /**
-   * Parameters:
-   * 0: the name of the requested named parameter
-   */
-  // #### Description
-  //
-  // The analyzer produces this diagnostic when a method or function invocation
-  // has a named argument, but the method or function being invoked doesn’t
-  // define a parameter with the same name.
-  //
-  // #### Example
-  //
-  // The following code produces this diagnostic:
-  //
-  // ```dart
-  // class C {
-  //   m({int b}) {}
-  // }
-  // void f(C c) {
-  //   c.m([!a!]: 1);
-  // }
-  // ```
-  //
-  // #### Common fixes
-  //
-  // If the argument name is mistyped, then replace it with the correct name.
-  // The example above can be fixed by changing `a` to `b`:
-  //
-  // ```dart
-  // class C {
-  //   m({int b}) {}
-  // }
-  // void f(C c) {
-  //   c.m(b: 1);
-  // }
-  // ```
-  //
-  // If a subclass adds a parameter with the name in question, then cast the
-  // target to the subclass:
-  //
-  // ```dart
-  // class C {
-  //   m({int b}) {}
-  // }
-  // class D extends C {
-  //   m({int a, int b}) {}
-  // }
-  // void f(C c) {
-  //   (c as D).m(a: 1);
-  // }
-  // ```
-  //
-  // If the parameter should be added to the function, then add it:
-  //
-  // ```dart
-  // class C {
-  //   m({int a, int b}) {}
-  // }
-  // void f(C c) {
-  //   c.m(a: 1);
-  // }
-  // ```
-  static const StaticWarningCode UNDEFINED_NAMED_PARAMETER =
-      const StaticWarningCode('UNDEFINED_NAMED_PARAMETER',
-          "The named parameter '{0}' isn't defined.",
-          correction:
-              "Try correcting the name to an existing named parameter, or "
-              "defining a new parameter with this name.");
+  @Deprecated('Use CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER')
+  static const CompileTimeErrorCode UNDEFINED_NAMED_PARAMETER =
+      CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER;
 
   /**
    * For the purposes of experimenting with potential non-null type semantics.
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 1e9916c..5e2e26c 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -86,8 +86,7 @@
             CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP, element);
       }
     } else if (element is SpreadElement) {
-      var isNullAware = element.spreadOperator.type ==
-          TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
+      var isNullAware = element.isNullAware;
       Expression expression = element.expression;
       if (forList || forSet) {
         _verifySpreadForListOrSet(isNullAware, expression);
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index 634f41a..3d1dfab 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -352,7 +352,7 @@
         //
         //     <TFrom, TTo extends TFrom>
         //     <TFrom, TTo extends Iterable<TFrom>>
-        //     <T extends Clonable<T>>
+        //     <T extends Cloneable<T>>
         //
         DartType argType = typeArgs[i];
 
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e270587..f45a35a 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -15,7 +15,6 @@
         CompilationUnitImpl,
         ExtensionDeclarationImpl,
         MixinDeclarationImpl;
-import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/fasta/error_converter.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:front_end/src/fasta/messages.dart'
@@ -37,7 +36,6 @@
         messageInvalidThisInInitializer,
         messageMissingAssignableSelector,
         messageNativeClauseShouldBeAnnotation,
-        messageStaticConstructor,
         messageTypedefNotFunction,
         templateDuplicateLabelInSwitchStatement,
         templateExpectedButGot,
@@ -47,7 +45,7 @@
 import 'package:front_end/src/fasta/parser.dart'
     show
         Assert,
-        ClassKind,
+        DeclarationKind,
         FormalParameterKind,
         IdentifierContext,
         MemberKind,
@@ -277,11 +275,7 @@
           : (mixinDeclaration != null
               ? mixinDeclaration.name.name
               : extensionDeclaration.name?.name);
-      if (name?.lexeme == className && getOrSet == null) {
-        // This error is also reported in OutlineBuilder.beginMethod
-        handleRecoverableError(
-            messageStaticConstructor, staticToken, staticToken);
-      } else {
+      if (name?.lexeme != className || getOrSet != null) {
         modifiers.staticKeyword = staticToken;
       }
     }
@@ -649,8 +643,8 @@
   }
 
   @override
-  void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token leftBracket, Token rightBracket) {
+  void endClassOrMixinBody(DeclarationKind kind, int memberCount,
+      Token leftBracket, Token rightBracket) {
     // TODO(danrubel): consider renaming endClassOrMixinBody
     // to endClassOrMixinOrExtensionBody
     assert(optional('{', leftBracket));
@@ -834,11 +828,11 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
     assert(optional('factory', factoryKeyword));
     assert(optional(';', endToken) || optional('}', endToken));
-    debugEvent("FactoryMethod");
+    debugEvent("ClassFactoryMethod");
 
     FunctionBody body;
     Token separator;
@@ -885,15 +879,6 @@
           ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
     }
 
-    if (extensionDeclaration != null) {
-      // TODO(brianwilkerson) Decide how to handle constructor and field
-      //  declarations within extensions. They are invalid, but we might want to
-      //  resolve them in order to get navigation, search, etc.
-      errorReporter.errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
-          name ?? returnType);
-      return;
-    }
     currentDeclarationMembers.add(ast.constructorDeclaration(
         comment,
         metadata,
@@ -910,6 +895,71 @@
         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));
+    assert(optional(';', endToken) || optional('}', endToken));
+    debugEvent("ExtensionFactoryMethod");
+
+    Object bodyObject = pop();
+    FormalParameterList parameters = pop();
+    TypeParameterList typeParameters = pop();
+    Object constructorName = pop();
+    _Modifiers modifiers = pop();
+    List<Annotation> metadata = pop();
+
+    FunctionBody body;
+    if (bodyObject is FunctionBody) {
+      body = bodyObject;
+    } else if (bodyObject is _RedirectingFactoryBody) {
+      body = ast.emptyFunctionBody(endToken);
+    } else {
+      // Unhandled situation which should never happen.
+      // Since this event handler is just a recovery attempt,
+      // don't bother adding this declaration to the AST.
+      return;
+    }
+    Comment comment = _findComment(metadata, beginToken);
+
+    assert(parameters != null);
+
+    // Constructor declarations within extensions are invalid and the parser
+    // has already reported an error at this point, but we include them in as
+    // a method declaration in order to get navigation, search, etc.
+
+    SimpleIdentifier methodName;
+    if (constructorName is SimpleIdentifier) {
+      methodName = constructorName;
+    } else if (constructorName is PrefixedIdentifier) {
+      methodName = constructorName.identifier;
+    } else {
+      // Unsure what the method name should be in this situation.
+      // Since this event handler is just a recovery attempt,
+      // don't bother adding this declaration to the AST.
+      return;
+    }
+    currentDeclarationMembers.add(ast.methodDeclaration(
+        comment,
+        metadata,
+        modifiers?.externalKeyword,
+        modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
+        null, // returnType
+        null, // getOrSet
+        null, // operatorKeyword
+        methodName,
+        typeParameters,
+        parameters,
+        body));
+  }
+
   void endFieldInitializer(Token assignment, Token token) {
     assert(optional('=', assignment));
     debugEvent("FieldInitializer");
@@ -920,7 +970,7 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token semicolon) {
     assert(optional(';', semicolon));
     debugEvent("Fields");
@@ -936,17 +986,6 @@
     Token covariantKeyword = covariantToken;
     List<Annotation> metadata = pop();
     Comment comment = _findComment(metadata, beginToken);
-    if (extensionDeclaration != null && staticToken == null) {
-      // TODO(brianwilkerson) Decide how to handle constructor and field
-      //  declarations within extensions. They are invalid, but we might want to
-      //  resolve them in order to get navigation, search, etc.
-      for (VariableDeclaration variable in variables) {
-        errorReporter.errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
-            variable.name);
-      }
-      return;
-    }
     currentDeclarationMembers.add(ast.fieldDeclaration2(
         comment: comment,
         metadata: metadata,
@@ -957,6 +996,32 @@
   }
 
   @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,
+      Token covariantToken,
+      Token lateToken,
+      Token varFinalOrConst,
+      int count,
+      Token beginToken,
+      Token endToken) {
+    if (staticToken == null) {
+      // TODO(danrubel) Decide how to handle instance field declarations
+      // within extensions. They are invalid and the parser has already reported
+      // an error at this point, but we include them in order to get navigation,
+      // search, etc.
+    }
+    endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+        count, beginToken, endToken);
+  }
+
+  @override
   void endForControlFlow(Token token) {
     debugEvent("endForControlFlow");
     var entry = pop();
@@ -1499,12 +1564,90 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     assert(getOrSet == null ||
         optional('get', getOrSet) ||
         optional('set', getOrSet));
-    debugEvent("Method");
+    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();
+    }
+
+    if (modifiers?.constKeyword != null) {
+      // This error is also reported in OutlineBuilder.endMethod
+      handleRecoverableError(
+          messageConstMethod, modifiers.constKeyword, modifiers.constKeyword);
+    }
+    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 [];
@@ -1532,97 +1675,78 @@
           beginToken.charOffset, uri);
     }
 
-    void constructor(
-        SimpleIdentifier prefixOrName, Token period, SimpleIdentifier name) {
-      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,
-          name,
-          parameters,
-          separator,
-          initializers,
-          redirectedConstructor,
-          body);
-      if (extensionDeclaration != null) {
-        // TODO(brianwilkerson) Decide how to handle constructor and field
-        //  declarations within extensions. They are invalid, but we might want
-        //  to resolve them in order to get navigation, search, etc.
-        errorReporter.errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
-            name ?? prefixOrName);
-        return;
-      }
-      currentDeclarationMembers.add(constructor);
-      if (mixinDeclaration != null) {
-        // TODO (danrubel): Report an error if this is a mixin declaration.
-      }
-    }
-
-    void method(Token operatorKeyword, SimpleIdentifier name) {
-      if (modifiers?.constKeyword != null) {
-        // This error is also reported in OutlineBuilder.endMethod
-        handleRecoverableError(
-            messageConstMethod, modifiers.constKeyword, modifiers.constKeyword);
-      }
-      checkFieldFormalParameters(parameters);
-      if (extensionDeclaration != null && body is EmptyFunctionBody) {
-        errorReporter.errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, name);
-        return;
-      }
-      currentDeclarationMembers.add(ast.methodDeclaration(
-          comment,
-          metadata,
-          modifiers?.externalKeyword,
-          modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
-          returnType,
-          getOrSet,
-          operatorKeyword,
-          name,
-          typeParameters,
-          parameters,
-          body));
-    }
-
+    SimpleIdentifier prefixOrName;
+    Token period;
+    SimpleIdentifier nameOrNull;
     if (name is SimpleIdentifier) {
-      if (name.name == currentDeclarationName?.name && getOrSet == null) {
-        constructor(name, null, null);
-      } else if (initializers.isNotEmpty && getOrSet == null) {
-        constructor(name, null, null);
-      } else {
-        method(null, name);
-      }
-    } else if (name is _OperatorName) {
-      method(name.operatorKeyword, name.name);
+      prefixOrName = name;
     } else if (name is PrefixedIdentifier) {
-      constructor(name.prefix, name.period, name.identifier);
+      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");
+    // TODO(danrubel) Decide how to handle constructor declarations within
+    // mixins. They are invalid, but we include them in order to get navigation,
+    // search, etc. Currently the error is reported by multiple listeners,
+    // but should be moved into the parser.
+    endClassConstructor(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @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.
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/declaration_resolver.dart b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
index 0ffaae8..6184e13 100644
--- a/pkg/analyzer/lib/src/generated/declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -299,6 +298,14 @@
         _walk(new ElementWalker.forGenericFunctionType(element), () {
           super.visitGenericFunctionType(node);
         });
+      } else {
+        var builder = new LocalElementBuilder(ElementHolder(), _enclosingUnit);
+        node.accept(builder);
+
+        var nodeImpl = node as GenericFunctionTypeImpl;
+        _enclosingUnit.encloseElement(
+          nodeImpl.declaredElement as GenericFunctionTypeElementImpl,
+        );
       }
     }
   }
@@ -561,168 +568,6 @@
     _walker = outerWalker;
   }
 
-  /// Apply the [type] that is created by the [constructorName] and the
-  /// [constructorElement] it references.
-  static void applyConstructorElement(
-      LibraryElement enclosingLibraryElement,
-      PrefixElement prefixElement,
-      ConstructorElement constructorElement,
-      DartType type,
-      ConstructorName constructorName) {
-    constructorName.staticElement = constructorElement;
-
-    ClassElement classElement = constructorElement?.enclosingElement;
-
-    Identifier typeIdentifier = constructorName.type.name;
-    if (prefixElement != null) {
-      PrefixedIdentifier prefixedTypeIdentifier = typeIdentifier;
-      prefixedTypeIdentifier.staticType = type;
-
-      prefixedTypeIdentifier.prefix.staticElement = prefixElement;
-
-      SimpleIdentifier classNode = prefixedTypeIdentifier.identifier;
-      classNode.staticElement = classElement;
-      classNode.staticType = type;
-    } else {
-      if (typeIdentifier is SimpleIdentifier) {
-        typeIdentifier.staticElement = classElement;
-        typeIdentifier.staticType = type;
-      } else if (typeIdentifier is PrefixedIdentifier) {
-        constructorName.type = astFactory.typeName(typeIdentifier.prefix, null);
-        constructorName.period = typeIdentifier.period;
-        constructorName.name = typeIdentifier.identifier;
-      }
-    }
-
-    constructorName.name?.staticElement = constructorElement;
-
-    DeclarationResolver.applyToTypeAnnotation(
-        enclosingLibraryElement, type, constructorName.type);
-  }
-
-  /// Apply the types of the [parameterElements] to the [parameterList] that
-  /// have an explicit type annotation.
-  static void applyParameters(
-      LibraryElement enclosingLibraryElement,
-      List<ParameterElement> parameterElements,
-      FormalParameterList parameterList) {
-    List<FormalParameter> parameters = parameterList.parameters;
-
-    int length = parameterElements.length;
-    if (parameters.length != length) {
-      throw new StateError('Parameter counts do not match');
-    }
-    for (int i = 0; i < length; i++) {
-      ParameterElementImpl element = parameterElements[i];
-      FormalParameter parameter = parameters[i];
-
-      DeclarationResolver.resolveMetadata(
-          parameter, parameter.metadata, element);
-
-      NormalFormalParameter normalParameter;
-      if (parameter is NormalFormalParameter) {
-        normalParameter = parameter;
-      } else if (parameter is DefaultFormalParameter) {
-        normalParameter = parameter.parameter;
-      }
-      assert(normalParameter != null);
-
-      if (normalParameter is SimpleFormalParameterImpl) {
-        normalParameter.declaredElement = element;
-      }
-
-      if (normalParameter.identifier != null) {
-        element.nameOffset = normalParameter.identifier.offset;
-        normalParameter.identifier.staticElement = element;
-        normalParameter.identifier.staticType = element.type;
-      }
-
-      // Apply the type or the return type, if a function typed parameter.
-      TypeAnnotation functionReturnType;
-      FormalParameterList functionParameterList;
-      if (normalParameter is SimpleFormalParameter) {
-        applyToTypeAnnotation(
-            enclosingLibraryElement, element.type, normalParameter.type);
-      } else if (normalParameter is FunctionTypedFormalParameter) {
-        functionReturnType = normalParameter.returnType;
-        functionParameterList = normalParameter.parameters;
-      } else if (normalParameter is FieldFormalParameter) {
-        if (normalParameter.parameters == null) {
-          applyToTypeAnnotation(
-              enclosingLibraryElement, element.type, normalParameter.type);
-        } else {
-          functionReturnType = normalParameter.type;
-          functionParameterList = normalParameter.parameters;
-        }
-      }
-
-      if (functionParameterList != null) {
-        FunctionType elementType = element.type;
-        if (functionReturnType != null) {
-          applyToTypeAnnotation(enclosingLibraryElement, elementType.returnType,
-              functionReturnType);
-        }
-        applyParameters(enclosingLibraryElement, elementType.parameters,
-            functionParameterList);
-      }
-    }
-  }
-
-  /// Apply the [type] to the [typeAnnotation] by setting the type of the
-  /// [typeAnnotation] to the [type] and recursively applying each of the type
-  /// arguments of the [type] to the corresponding type arguments of the
-  /// [typeAnnotation].
-  static void applyToTypeAnnotation(LibraryElement enclosingLibraryElement,
-      DartType type, TypeAnnotation typeAnnotation) {
-    if (typeAnnotation is GenericFunctionTypeImpl) {
-      if (type is! FunctionType) {
-        throw new StateError('Non-function type ($type) '
-            'for generic function annotation ($typeAnnotation)');
-      }
-      FunctionType functionType = type;
-      typeAnnotation.type = type;
-      applyToTypeAnnotation(enclosingLibraryElement, functionType.returnType,
-          typeAnnotation.returnType);
-      applyParameters(enclosingLibraryElement, functionType.parameters,
-          typeAnnotation.parameters);
-    } else if (typeAnnotation is TypeNameImpl) {
-      typeAnnotation.type = type;
-
-      Identifier typeIdentifier = typeAnnotation.name;
-      SimpleIdentifier typeName;
-      if (typeIdentifier is PrefixedIdentifier) {
-        if (enclosingLibraryElement != null) {
-          String prefixName = typeIdentifier.prefix.name;
-          for (var import in enclosingLibraryElement.imports) {
-            if (import.prefix?.name == prefixName) {
-              typeIdentifier.prefix.staticElement = import.prefix;
-              break;
-            }
-          }
-        }
-        typeName = typeIdentifier.identifier;
-      } else {
-        typeName = typeIdentifier;
-      }
-
-      Element typeElement = type.element;
-      if (typeElement is GenericFunctionTypeElement &&
-          typeElement.enclosingElement is GenericTypeAliasElement) {
-        typeElement = typeElement.enclosingElement;
-      }
-
-      typeName.staticElement = typeElement;
-      typeName.staticType = type;
-    }
-    if (typeAnnotation is NamedType) {
-      TypeArgumentList typeArguments = typeAnnotation.typeArguments;
-      if (typeArguments != null) {
-        _applyTypeArgumentsToList(
-            enclosingLibraryElement, type, typeArguments.arguments);
-      }
-    }
-  }
-
   /// Associate each of the annotation [nodes] with the corresponding
   /// [ElementAnnotation] in [annotations]. If there is a problem, report it
   /// against the given [parent] node.
@@ -752,31 +597,6 @@
     }
   }
 
-  /// Recursively apply each of the type arguments of the [type] to the
-  /// corresponding type arguments of the [typeArguments].
-  static void _applyTypeArgumentsToList(LibraryElement enclosingLibraryElement,
-      DartType type, List<TypeAnnotation> typeArguments) {
-    if (type != null && type.isDynamic) {
-      for (TypeAnnotation argument in typeArguments) {
-        applyToTypeAnnotation(enclosingLibraryElement, type, argument);
-      }
-    } else if (type is ParameterizedType) {
-      List<DartType> argumentTypes = type.typeArguments;
-      int argumentCount = argumentTypes.length;
-      if (argumentCount != typeArguments.length) {
-        throw new StateError('Found $argumentCount argument types '
-            'for ${typeArguments.length} type arguments');
-      }
-      for (int i = 0; i < argumentCount; i++) {
-        applyToTypeAnnotation(
-            enclosingLibraryElement, argumentTypes[i], typeArguments[i]);
-      }
-    } else {
-      throw new StateError('Attempting to apply a non-parameterized type '
-          '(${type.runtimeType}) to type arguments');
-    }
-  }
-
   static bool _isBodyToCreateElementsFor(FunctionBody node) {
     AstNode parent = node.parent;
     return parent is ConstructorDeclaration ||
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 7653e61..8518284 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -114,6 +114,7 @@
   InterfaceType _typeType;
 
   /// Whether constant evaluation errors should be reported during resolution.
+  @Deprecated('This field is no longer used')
   final bool reportConstEvaluationErrors;
 
   /// Helper for extension method resolution.
@@ -174,7 +175,7 @@
         //  side to the operator.
         ResolutionResult result =
             _lookUpMethod(leftHandSide, staticType, methodName, leftHandSide);
-        node.staticElement = result.element;
+        node.staticElement = result.function;
         if (_shouldReportInvalidMember(staticType, result)) {
           _recordUndefinedToken(
               staticType.element,
@@ -271,8 +272,7 @@
               memberElement = element.getNamedConstructor(name.name);
               if (memberElement == null) {
                 memberElement =
-                    _lookUpSetter(prefix, element.type, name.name, name)
-                        .element;
+                    _lookUpSetter(prefix, element.type, name.name, name).setter;
               }
             }
             if (memberElement == null) {
@@ -405,8 +405,7 @@
     Expression function = node.function;
     DartType functionType;
     if (function is ExtensionOverride) {
-      var member = _extensionResolver.getOverrideMember(
-          function, 'call', ElementKind.METHOD);
+      var member = _extensionResolver.getOverrideMember(function, 'call');
       if (member != null && member.isStatic) {
         _resolver.errorReporter.reportErrorForNode(
             CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
@@ -485,7 +484,7 @@
       ResolutionResult setterResult =
           _lookUpMethod(target, staticType, setterMethodName, target);
       // set setter element
-      node.staticElement = setterResult.element;
+      node.staticElement = setterResult.function;
       // generate undefined method warning
       _checkForUndefinedIndexOperator(
           node, target, setterMethodName, setterResult, staticType);
@@ -494,7 +493,7 @@
           _lookUpMethod(target, staticType, getterMethodName, target);
       // set getter element
       AuxiliaryElements auxiliaryElements =
-          new AuxiliaryElements(getterResult.element, null);
+          new AuxiliaryElements(getterResult.function, null);
       node.auxiliaryElements = auxiliaryElements;
       // generate undefined method warning
       _checkForUndefinedIndexOperator(
@@ -504,7 +503,7 @@
       ResolutionResult methodResult =
           _lookUpMethod(target, staticType, getterMethodName, target);
       // set getter element
-      node.staticElement = methodResult.element;
+      node.staticElement = methodResult.function;
       // generate undefined method warning
       _checkForUndefinedIndexOperator(
           node, target, getterMethodName, methodResult, staticType);
@@ -513,7 +512,7 @@
       ResolutionResult methodResult =
           _lookUpMethod(target, staticType, setterMethodName, target);
       // set setter element
-      node.staticElement = methodResult.element;
+      node.staticElement = methodResult.function;
       // generate undefined method warning
       _checkForUndefinedIndexOperator(
           node, target, setterMethodName, methodResult, staticType);
@@ -525,10 +524,8 @@
     ConstructorElement invokedConstructor = node.constructorName.staticElement;
     node.staticElement = invokedConstructor;
     ArgumentList argumentList = node.argumentList;
-    List<ParameterElement> parameters = _resolveArgumentsToFunction(
-        reportConstEvaluationErrors && node.isConst,
-        argumentList,
-        invokedConstructor);
+    List<ParameterElement> parameters =
+        _resolveArgumentsToFunction(argumentList, invokedConstructor);
     if (parameters != null) {
       argumentList.correspondingStaticParameters = parameters;
     }
@@ -573,7 +570,7 @@
     //  the operator.
     ResolutionResult result =
         _lookUpMethod(operand, staticType, methodName, operand);
-    node.staticElement = result.element;
+    node.staticElement = result.function;
     if (_shouldReportInvalidMember(staticType, result)) {
       if (operand is SuperExpression) {
         _recordUndefinedToken(
@@ -681,7 +678,7 @@
       //  the operator.
       ResolutionResult result =
           _lookUpMethod(operand, staticType, methodName, operand);
-      node.staticElement = result.element;
+      node.staticElement = result.function;
       if (_shouldReportInvalidMember(staticType, result)) {
         if (operand is SuperExpression) {
           _recordUndefinedToken(
@@ -717,7 +714,10 @@
       ExecutableElement member;
       if (propertyName.inSetterContext()) {
         member = _extensionResolver.getOverrideMember(
-            target, memberName, ElementKind.SETTER);
+          target,
+          memberName,
+          setter: true,
+        );
         if (member == null) {
           _resolver.errorReporter.reportErrorForNode(
               CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
@@ -725,8 +725,8 @@
               [memberName, element.name]);
         }
         if (propertyName.inGetterContext()) {
-          PropertyAccessorElement getter = _extensionResolver.getOverrideMember(
-              target, memberName, ElementKind.GETTER);
+          PropertyAccessorElement getter =
+              _extensionResolver.getOverrideMember(target, memberName);
           if (getter == null) {
             _resolver.errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
@@ -736,10 +736,7 @@
           propertyName.auxiliaryElements = AuxiliaryElements(getter, null);
         }
       } else if (propertyName.inGetterContext()) {
-        member = _extensionResolver.getOverrideMember(
-                target, memberName, ElementKind.GETTER) ??
-            _extensionResolver.getOverrideMember(
-                target, memberName, ElementKind.METHOD);
+        member = _extensionResolver.getOverrideMember(target, memberName);
         if (member == null) {
           _resolver.errorReporter.reportErrorForNode(
               CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
@@ -786,7 +783,7 @@
     node.staticElement = element;
     ArgumentList argumentList = node.argumentList;
     List<ParameterElement> parameters =
-        _resolveArgumentsToFunction(false, argumentList, element);
+        _resolveArgumentsToFunction(argumentList, element);
     if (parameters != null) {
       argumentList.correspondingStaticParameters = parameters;
     }
@@ -878,7 +875,7 @@
         enclosingClass != null) {
       InterfaceType enclosingType = enclosingClass.type;
       AuxiliaryElements auxiliaryElements = new AuxiliaryElements(
-          _lookUpGetter(null, enclosingType, node.name, node).element, null);
+          _lookUpGetter(null, enclosingType, node.name, node).getter, null);
       node.auxiliaryElements = auxiliaryElements;
     }
     //
@@ -939,8 +936,8 @@
       return;
     }
     ArgumentList argumentList = node.argumentList;
-    List<ParameterElement> parameters = _resolveArgumentsToFunction(
-        isInConstConstructor, argumentList, element);
+    List<ParameterElement> parameters =
+        _resolveArgumentsToFunction(argumentList, element);
     if (parameters != null) {
       argumentList.correspondingStaticParameters = parameters;
     }
@@ -1020,11 +1017,10 @@
     if (type is InterfaceType) {
       MethodElement callMethod = invocation.staticElement;
       if (callMethod != null) {
-        return _resolveArgumentsToFunction(false, argumentList, callMethod);
+        return _resolveArgumentsToFunction(argumentList, callMethod);
       }
     } else if (type is FunctionType) {
-      return _resolveArgumentsToParameters(
-          false, argumentList, type.parameters);
+      return _resolveArgumentsToParameters(argumentList, type.parameters);
     }
     return null;
   }
@@ -1229,12 +1225,8 @@
     }
 
     var result = _extensionResolver.findExtension(
-      type,
-      FunctionElement.CALL_METHOD_NAME,
-      node,
-      ElementKind.METHOD,
-    );
-    var instantiatedMember = result.element;
+        type, FunctionElement.CALL_METHOD_NAME, node);
+    var instantiatedMember = result.function;
     if (instantiatedMember is MethodElement) {
       return instantiatedMember;
     }
@@ -1256,7 +1248,7 @@
       var getter = type.lookUpInheritedGetter(name,
           library: _definingLibrary, thisType: target is! SuperExpression);
       if (getter != null) {
-        result = ResolutionResult(getter);
+        result = ResolutionResult(property: getter.variable);
       }
     }
 
@@ -1268,8 +1260,7 @@
       return ResolutionResult.none;
     }
     if (result.isNone) {
-      result = _extensionResolver.findExtension(
-          type, name, nameNode, ElementKind.GETTER);
+      result = _extensionResolver.findExtension(type, name, nameNode);
     }
     return result;
   }
@@ -1302,7 +1293,7 @@
       var method = type.lookUpInheritedMethod(name,
           library: _definingLibrary, thisType: target is! SuperExpression);
       if (method != null) {
-        result = ResolutionResult(method);
+        result = ResolutionResult(function: method);
       }
     }
 
@@ -1314,8 +1305,7 @@
       return ResolutionResult.none;
     }
     if (result.isNone) {
-      result = _extensionResolver.findExtension(
-          type, name, nameNode, ElementKind.METHOD);
+      result = _extensionResolver.findExtension(type, name, nameNode);
     }
     return result;
   }
@@ -1334,7 +1324,7 @@
       var setter = type.lookUpInheritedSetter(name,
           library: _definingLibrary, thisType: target is! SuperExpression);
       if (setter != null) {
-        result = ResolutionResult(setter);
+        result = ResolutionResult(property: setter.variable);
       }
     }
 
@@ -1346,8 +1336,7 @@
       return ResolutionResult.none;
     }
     if (result.isNone) {
-      result = _extensionResolver.findExtension(
-          type, name, nameNode, ElementKind.SETTER);
+      result = _extensionResolver.findExtension(type, name, nameNode);
     }
     return result;
   }
@@ -1401,7 +1390,7 @@
     }
     // resolve arguments to parameters
     List<ParameterElement> parameters =
-        _resolveArgumentsToFunction(true, argumentList, constructor);
+        _resolveArgumentsToFunction(argumentList, constructor);
     if (parameters != null) {
       argumentList.correspondingStaticParameters = parameters;
     }
@@ -1543,35 +1532,29 @@
    * Given an [argumentList] and the [executableElement] that will be invoked
    * using those argument, compute the list of parameters that correspond to the
    * list of arguments. An error will be reported if any of the arguments cannot
-   * be matched to a parameter. The flag [reportAsError] should be `true` if a
-   * compile-time error should be reported; or `false` if a compile-time warning
-   * should be reported. Return the parameters that correspond to the arguments,
-   * or `null` if no correspondence could be computed.
+   * be matched to a parameter. Return the parameters that correspond to the
+   * arguments, or `null` if no correspondence could be computed.
    */
-  List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
+  List<ParameterElement> _resolveArgumentsToFunction(
       ArgumentList argumentList, ExecutableElement executableElement) {
     if (executableElement == null) {
       return null;
     }
     List<ParameterElement> parameters = executableElement.parameters;
-    return _resolveArgumentsToParameters(
-        reportAsError, argumentList, parameters);
+    return _resolveArgumentsToParameters(argumentList, parameters);
   }
 
   /**
    * Given an [argumentList] and the [parameters] related to the element that
    * will be invoked using those arguments, compute the list of parameters that
    * correspond to the list of arguments. An error will be reported if any of
-   * the arguments cannot be matched to a parameter. The flag [reportAsError]
-   * should be `true` if a compile-time error should be reported; or `false` if
-   * a compile-time warning should be reported. Return the parameters that
+   * the arguments cannot be matched to a parameter. Return the parameters that
    * correspond to the arguments.
    */
-  List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
+  List<ParameterElement> _resolveArgumentsToParameters(
       ArgumentList argumentList, List<ParameterElement> parameters) {
     return ResolverVisitor.resolveArgumentsToParameters(
-        argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
-        reportAsError: reportAsError);
+        argumentList, parameters, _resolver.errorReporter.reportErrorForNode);
   }
 
   void _resolveBinaryExpression(BinaryExpression node, String methodName) {
@@ -1601,7 +1584,7 @@
           forSuper: isSuper,
         );
         if (invokeElement != null) {
-          result = ResolutionResult(invokeElement);
+          result = ResolutionResult(function: invokeElement);
         }
       }
 
@@ -1612,12 +1595,11 @@
       }
 
       if (result.isNone) {
-        result = _extensionResolver.findExtension(
-            leftType, methodName, node, ElementKind.METHOD);
+        result = _extensionResolver.findExtension(leftType, methodName, node);
       }
 
-      node.staticElement = result.element;
-      node.staticInvokeType = result.element?.type;
+      node.staticElement = result.function;
+      node.staticInvokeType = result.function?.type;
       if (_shouldReportInvalidMember(leftType, result)) {
         if (isSuper) {
           _recordUndefinedToken(
@@ -1678,23 +1660,28 @@
    * Given that we are accessing a property of the given [classElement] with the
    * given [propertyName], return the element that represents the property.
    */
-  Element _resolveElement(
+  ResolutionResult _resolveElement(
       ClassElement classElement, SimpleIdentifier propertyName) {
     String name = propertyName.name;
-    Element element = null;
     if (propertyName.inSetterContext()) {
-      element = classElement.getSetter(name);
+      var element = classElement.getSetter(name);
+      if (element != null && element.isAccessibleIn(_definingLibrary)) {
+        return ResolutionResult(property: element.variable);
+      }
     }
-    if (element == null) {
-      element = classElement.getGetter(name);
+    {
+      var element = classElement.getGetter(name);
+      if (element != null && element.isAccessibleIn(_definingLibrary)) {
+        return ResolutionResult(property: element.variable);
+      }
     }
-    if (element == null) {
-      element = classElement.getMethod(name);
+    {
+      var element = classElement.getMethod(name);
+      if (element != null && element.isAccessibleIn(_definingLibrary)) {
+        return ResolutionResult(function: element);
+      }
     }
-    if (element != null && element.isAccessibleIn(_definingLibrary)) {
-      return element;
-    }
-    return null;
+    return ResolutionResult.none;
   }
 
   /**
@@ -1765,7 +1752,11 @@
             [memberName]);
       }
       if (staticElement != null) {
-        result = ResolutionResult(staticElement);
+        if (staticElement is PropertyAccessorElement) {
+          result = ResolutionResult(property: staticElement.variable);
+        } else if (staticElement is MethodElement) {
+          result = ResolutionResult(function: staticElement);
+        }
       }
     }
     //
@@ -1775,18 +1766,15 @@
     // does not apply to conditional property accesses (i.e. 'C?.m').
     //
     if (result.isNone) {
-      Element staticElement;
       ClassElement typeReference = getTypeReference(target);
       if (typeReference != null) {
         if (isCascaded) {
           typeReference = _typeType.element;
         }
-        staticElement = _resolveElement(typeReference, propertyName);
-        if (staticElement != null) {
-          result = ResolutionResult(staticElement);
-        }
+        result = _resolveElement(typeReference, propertyName);
       } else {
         if (target is SuperExpression) {
+          ExecutableElement staticElement;
           if (staticType is InterfaceTypeImpl) {
             staticElement = staticType.lookUpInheritedMember(
                 propertyName.name, _definingLibrary,
@@ -1814,8 +1802,10 @@
               }
             }
           }
-          if (staticElement != null) {
-            result = ResolutionResult(staticElement);
+          if (staticElement is PropertyAccessorElement) {
+            result = ResolutionResult(property: staticElement.variable);
+          } else if (staticElement is MethodElement) {
+            result = ResolutionResult(function: staticElement);
           }
         } else {
           result = _resolveProperty(target, staticType, propertyName);
@@ -1826,11 +1816,13 @@
     // Error was already reported in validateAnnotationElement().
     if (target.parent.parent is Annotation) {
       if (result.isSingle) {
-        propertyName.staticElement = result.element;
+        propertyName.staticElement = result.getter;
       }
       return;
     }
-    propertyName.staticElement = result.element;
+    propertyName.staticElement =
+        (propertyName.inSetterContext() ? result.setter : null) ??
+            result.getter;
     if (_shouldReportInvalidMember(staticType, result)) {
       if (staticType is FunctionType &&
           propertyName.name == FunctionElement.CALL_METHOD_NAME) {
@@ -1917,7 +1909,7 @@
           if (enclosingClass != null) {
             setter = _lookUpSetter(
                     null, enclosingClass.type, identifier.name, identifier)
-                .element;
+                .setter;
           }
         }
         if (setter != null) {
@@ -1957,17 +1949,17 @@
                 identifier.parent is CommentReference)) {
           element =
               _lookUpSetter(null, enclosingType, identifier.name, identifier)
-                  .element;
+                  .setter;
         }
         if (element == null && identifier.inGetterContext()) {
           element =
               _lookUpGetter(null, enclosingType, identifier.name, identifier)
-                  .element;
+                  .getter;
         }
         if (element == null) {
           element =
               _lookUpMethod(null, enclosingType, identifier.name, identifier)
-                  .element;
+                  .getter;
         }
       }
     }
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index fd4540d..dd79796 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -30,7 +30,6 @@
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/manager.dart';
 import 'package:front_end/src/fasta/scanner/token.dart';
 import 'package:path/path.dart' as pathos;
 import 'package:pub_semver/pub_semver.dart';
@@ -144,10 +143,6 @@
   /// [name].
   set name(String name);
 
-  /// The stream that is notified when sources have been added or removed,
-  /// or the source's content has changed.
-  Stream<SourcesChangedEvent> get onSourcesChanged;
-
   /// Return the source factory used to create the sources that can be analyzed
   /// in this context.
   SourceFactory get sourceFactory;
@@ -255,10 +250,6 @@
   CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
       Source source, Source librarySource);
 
-  /// Perform work until the given [result] has been computed for the given
-  /// [target]. Return the computed value.
-  V computeResult<V>(AnalysisTarget target, ResultDescriptor<V> result);
-
   /// Notifies the context that the client is going to stop using this context.
   void dispose();
 
@@ -277,13 +268,6 @@
   CompilationUnitElement getCompilationUnitElement(
       Source unitSource, Source librarySource);
 
-  /// Return configuration data associated with the given key or the [key]'s
-  /// default value if no state has been associated.
-  ///
-  /// See [setConfigurationData].
-  @deprecated
-  V getConfigurationData<V>(ResultDescriptor<V> key);
-
   /// Return the contents and timestamp of the given [source].
   ///
   /// This method should be used rather than the method [Source.getContents]
@@ -379,12 +363,6 @@
   CompilationUnit getResolvedCompilationUnit2(
       Source unitSource, Source librarySource);
 
-  /// Return the value of the given [result] for the given [target].
-  ///
-  /// If the corresponding [target] does not exist, or the [result] is not
-  /// computed yet, then the default value is returned.
-  V getResult<V>(AnalysisTarget target, ResultDescriptor<V> result);
-
   /// Return a list of the sources being analyzed in this context whose full path
   /// is equal to the given [path].
   List<Source> getSourcesWithFullName(String path);
@@ -412,15 +390,6 @@
   /// or if we do not know whether it can be run on the server.
   bool isServerLibrary(Source librarySource);
 
-  /// Return the stream that is notified when a result with the given
-  /// [descriptor] is changed, e.g. computed or invalidated.
-  Stream<ResultChangedEvent> onResultChanged(ResultDescriptor descriptor);
-
-  /// Return the stream that is notified when a new value for the given
-  /// [descriptor] is computed.
-  @deprecated
-  Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor);
-
   /// Parse the content of the given [source] to produce an AST structure. The
   /// resulting AST structure may or may not be resolved, and may have a slightly
   /// different structure depending upon whether it is resolved.
@@ -482,12 +451,6 @@
   void setChangedContents(
       Source source, String contents, int offset, int oldLength, int newLength);
 
-  /// Associate this configuration [data] object with the given descriptor [key].
-  ///
-  /// See [getConfigurationData].
-  @deprecated
-  void setConfigurationData(ResultDescriptor key, Object data);
-
   /// Set the contents of the given [source] to the given [contents] and mark the
   /// source as having changed. This has the effect of overriding the default
   /// contents of the source. If the contents are `null` the override is removed
@@ -597,9 +560,6 @@
   /// The partition manager being used to manage the shared partitions.
   final PartitionManager partitionManager = new PartitionManager();
 
-  /// The task manager used to manage the tasks used to analyze code.
-  TaskManager _taskManager;
-
   AnalysisEngine._();
 
   /// Return the instrumentation service that is to be used by this analysis
@@ -626,14 +586,6 @@
     this._logger = logger ?? Logger.NULL;
   }
 
-  /// Return the task manager used to manage the tasks used to analyze code.
-  TaskManager get taskManager {
-    if (_taskManager == null) {
-      _taskManager = new TaskManager();
-    }
-    return _taskManager;
-  }
-
   /// Clear any caches holding on to analysis results so that a full re-analysis
   /// will be performed the next time an analysis context is created.
   void clearCaches() {
@@ -938,6 +890,9 @@
   /// Return `true` if analyzer should use the Dart 2.0 Front End parser.
   bool get useFastaParser;
 
+  /// Return `true` the lint with the given [name] is enabled.
+  bool isLintEnabled(String name);
+
   /// Reset the state of this set of analysis options to its original state.
   void resetToDefaults();
 
@@ -1350,6 +1305,11 @@
   }
 
   @override
+  bool isLintEnabled(String name) {
+    return lintRules.any((rule) => rule.name == name);
+  }
+
+  @override
   void resetToDefaults() {
     dart2jsHint = false;
     disableCacheFlushing = false;
@@ -1800,27 +1760,6 @@
       this.contents, this.offset, this.oldLength, this.newLength);
 }
 
-/// [ComputedResult] describes a value computed for a [ResultDescriptor].
-@deprecated
-class ComputedResult<V> {
-  /// The context in which the value was computed.
-  final AnalysisContext context;
-
-  /// The descriptor of the result which was computed.
-  final ResultDescriptor<V> descriptor;
-
-  /// The target for which the result was computed.
-  final AnalysisTarget target;
-
-  /// The computed value.
-  final V value;
-
-  ComputedResult(this.context, this.descriptor, this.target, this.value);
-
-  @override
-  String toString() => 'Computed $descriptor of $target in $context';
-}
-
 /// An event indicating when a source either starts or stops being implicitly
 /// analyzed.
 class ImplicitAnalysisEvent {
@@ -1867,10 +1806,6 @@
   /// Specify whether the context is active, i.e. is being analyzed now.
   set isActive(bool value);
 
-  /// Return the [StreamController] reporting [InvalidatedResult]s for everything
-  /// in this context's cache.
-  ReentrantSynchronousStream<InvalidatedResult> get onResultInvalidated;
-
   /// Return a list containing all of the sources that have been marked as
   /// priority sources. Clients must not modify the returned list.
   List<Source> get prioritySources;
@@ -1885,19 +1820,6 @@
   /// Sets the [TypeProvider] for this context.
   void set typeProvider(TypeProvider typeProvider);
 
-  /// A list of all [WorkManager]s used by this context.
-  List<WorkManager> get workManagers;
-
-  /// This method is invoked when the state of the [result] of the [entry] is
-  /// [CacheState.INVALID], so it is about to be computed.
-  ///
-  /// If the context knows how to provide the value, it sets the value into
-  /// the [entry] with all required dependencies, and returns `true`.
-  ///
-  /// Otherwise, it returns `false` to indicate that the result should be
-  /// computed as usually.
-  bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result);
-
   /// Return a list containing the sources of the libraries that are exported by
   /// the library with the given [source]. The list will be empty if the given
   /// source is invalid, if the given source does not represent a library, or if
@@ -1921,9 +1843,6 @@
   /// will be eventually returned to the client from [performAnalysisTask].
   List<CompilationUnit> ensureResolvedDartUnits(Source source);
 
-  /// Return the cache entry associated with the given [target].
-  CacheEntry getCacheEntry(AnalysisTarget target);
-
   /// Return context that owns the given [source].
   InternalAnalysisContext getContextFor(Source source);
 
@@ -2190,80 +2109,3 @@
     node.accept(eraser);
   }
 }
-
-/// [ResultChangedEvent] describes a change to an analysis result.
-class ResultChangedEvent<V> {
-  /// The context in which the result was changed.
-  final AnalysisContext context;
-
-  /// The target for which the result was changed.
-  final AnalysisTarget target;
-
-  /// The descriptor of the result which was changed.
-  final ResultDescriptor<V> descriptor;
-
-  /// If the result [wasComputed], the new value of the result. If the result
-  /// [wasInvalidated], the value of before it was invalidated, may be the
-  /// default value if the result was flushed.
-  final V value;
-
-  /// Is `true` if the result was computed, or `false` is is was invalidated.
-  final bool _wasComputed;
-
-  ResultChangedEvent(this.context, this.target, this.descriptor, this.value,
-      this._wasComputed);
-
-  /// Returns `true` if the result was computed.
-  bool get wasComputed => _wasComputed;
-
-  /// Returns `true` if the result was invalidated.
-  bool get wasInvalidated => !_wasComputed;
-
-  @override
-  String toString() {
-    String operation = _wasComputed ? 'Computed' : 'Invalidated';
-    return '$operation $descriptor of $target in $context';
-  }
-}
-
-/// [SourcesChangedEvent] indicates which sources have been added, removed,
-/// or whose contents have changed.
-class SourcesChangedEvent {
-  /// The internal representation of what has changed. Clients should not access
-  /// this field directly.
-  final ChangeSet _changeSet;
-
-  /// Construct an instance representing the given changes.
-  SourcesChangedEvent(ChangeSet changeSet) : _changeSet = changeSet;
-
-  /// Construct an instance representing a source content change.
-  factory SourcesChangedEvent.changedContent(Source source, String contents) {
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.changedContent(source, contents);
-    return new SourcesChangedEvent(changeSet);
-  }
-
-  /// Construct an instance representing a source content change.
-  factory SourcesChangedEvent.changedRange(Source source, String contents,
-      int offset, int oldLength, int newLength) {
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.changedRange(source, contents, offset, oldLength, newLength);
-    return new SourcesChangedEvent(changeSet);
-  }
-
-  /// Return the collection of sources for which content has changed.
-  Iterable<Source> get changedSources {
-    List<Source> changedSources = new List.from(_changeSet.changedSources);
-    changedSources.addAll(_changeSet.changedContents.keys);
-    changedSources.addAll(_changeSet.changedRanges.keys);
-    return changedSources;
-  }
-
-  /// Return `true` if any sources were added.
-  bool get wereSourcesAdded => _changeSet.addedSources.isNotEmpty;
-
-  /// Return `true` if any sources were removed or deleted.
-  bool get wereSourcesRemoved =>
-      _changeSet.removedSources.isNotEmpty ||
-      _changeSet.removedContainers.isNotEmpty;
-}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 63c5052..3b1fd26 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -6,7 +6,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -419,7 +418,6 @@
         operatorType == TokenType.QUESTION_QUESTION_EQ) {
       _checkForInvalidAssignment(lhs, rhs);
     } else {
-      _checkForInvalidCompoundAssignment(node, lhs, rhs);
       _checkForArgumentTypeNotAssignableForArgument(rhs);
       _checkForNullableDereference(lhs);
     }
@@ -620,7 +618,6 @@
       _checkForConstConstructorWithNonConstSuper(node);
       _checkForAllFinalInitializedErrorCodes(node);
       _checkForRedirectingConstructorErrorCodes(node);
-      _checkForMixinDeclaresConstructor(node);
       _checkForMultipleSuperInitializers(node);
       _checkForRecursiveConstructorRedirect(node, constructorElement);
       if (!_checkForRecursiveFactoryRedirect(node, constructorElement)) {
@@ -733,7 +730,13 @@
   void visitExtensionDeclaration(ExtensionDeclaration node) {
     _enclosingExtension = node.declaredElement;
     _duplicateDefinitionVerifier.checkExtension(node);
+    _checkForFinalNotInitializedInClass(node.members);
     _checkForMismatchedAccessorTypesInExtension(node);
+    final name = node.name;
+    if (name != null) {
+      _checkForBuiltInIdentifierAsName(
+          name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME);
+    }
     super.visitExtensionDeclaration(node);
     _enclosingExtension = null;
   }
@@ -926,8 +929,7 @@
       // we can get the function element via `node?.element?.type?.element` but
       // it doesn't have hasImplicitReturnType set correctly.
       if (!_options.implicitDynamic && node.returnType == null) {
-        DartType parameterType =
-            resolutionMap.elementDeclaredByFormalParameter(node).type;
+        DartType parameterType = node.declaredElement.type;
         if (parameterType is FunctionType &&
             parameterType.returnType.isDynamic) {
           _errorReporter.reportErrorForNode(
@@ -994,7 +996,10 @@
   @override
   void visitIndexExpression(IndexExpression node) {
     _checkForArgumentTypeNotAssignableForArgument(node.index);
-    _checkForNullableDereference(node.target);
+    if (node.leftBracket.type !=
+        TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET) {
+      _checkForNullableDereference(node.target);
+    }
     super.visitIndexExpression(node);
   }
 
@@ -1295,7 +1300,7 @@
 
   @override
   void visitSpreadElement(SpreadElement node) {
-    if (node.spreadOperator.type != TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+    if (!node.isNullAware) {
       _checkForNullableDereference(node.expression);
     } else {
       _checkForUnnecessaryNullAware(node.expression, node.spreadOperator);
@@ -1757,10 +1762,6 @@
 
   /**
    * Check for errors related to the redirected constructors.
-   *
-   * See [StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE],
-   * [StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE], and
-   * [StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR].
    */
   void _checkForAllRedirectConstructorErrorCodes(
       ConstructorDeclaration declaration) {
@@ -1785,10 +1786,9 @@
         if (redirectedConstructor.name != null) {
           constructorStrName += ".${redirectedConstructor.name.name}";
         }
-        ErrorCode errorCode = (declaration.constKeyword != null
-            ? CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR
-            : StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR);
-        _errorReporter.reportErrorForNode(errorCode, redirectedConstructor,
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR,
+            redirectedConstructor,
             [constructorStrName, redirectedType.displayName]);
       }
       return;
@@ -1797,8 +1797,7 @@
     DartType redirectedReturnType = redirectedType.returnType;
 
     // Report specific problem when return type is incompatible
-    FunctionType constructorType =
-        resolutionMap.elementDeclaredByConstructorDeclaration(declaration).type;
+    FunctionType constructorType = declaration.declaredElement.type;
     DartType constructorReturnType = constructorType.returnType;
     if (!_typeSystem.isAssignableTo(redirectedReturnType, constructorReturnType,
         featureSet: _featureSet)) {
@@ -2088,7 +2087,7 @@
       if (element.isConst) {
         _errorReporter.reportErrorForNode(
             StaticWarningCode.ASSIGNMENT_TO_CONST, expression);
-      } else if (element.isFinal) {
+      } else if (element.isFinal && !element.isLate) {
         if (element is FieldElementImpl) {
           if (element.setter == null && element.isSynthetic) {
             _errorReporter.reportErrorForNode(
@@ -2159,7 +2158,8 @@
    * Verify that the given [identifier] is not a keyword, and generates the
    * given [errorCode] on the identifier if it is a keyword.
    *
-   * See [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME],
+   * See [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME],
+   * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME],
    * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME], and
    * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME].
    */
@@ -3473,27 +3473,6 @@
   }
 
   /**
-   * Given an [assignment] using a compound assignment operator, this verifies
-   * that the given assignment is valid. The [lhs] is the left hand side
-   * expression. The [rhs] is the right hand side expression.
-   *
-   * See [StaticTypeWarningCode.INVALID_ASSIGNMENT].
-   */
-  void _checkForInvalidCompoundAssignment(
-      AssignmentExpression assignment, Expression lhs, Expression rhs) {
-    if (lhs == null) {
-      return;
-    }
-    DartType leftType = getStaticType(lhs);
-    DartType rightType = getStaticType(assignment);
-    if (!_typeSystem.isAssignableTo(rightType, leftType,
-        featureSet: _featureSet)) {
-      _errorReporter.reportTypeErrorForNode(
-          StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]);
-    }
-  }
-
-  /**
    * Check the given [initializer] to ensure that the field being initialized is
    * a valid field. The [fieldName] is the field name from the
    * [ConstructorFieldInitializer]. The [staticElement] is the static element
@@ -3794,7 +3773,7 @@
   }
 
   void _checkForMissingJSLibAnnotation(Annotation node) {
-    if (resolutionMap.elementAnnotationForAnnotation(node)?.isJS ?? false) {
+    if (node.elementAnnotation?.isJS ?? false) {
       if (_currentLibrary.hasJS != true) {
         _errorReporter.reportErrorForNode(
             HintCode.MISSING_JS_LIB_ANNOTATION, node);
@@ -3847,13 +3826,6 @@
     return false;
   }
 
-  void _checkForMixinDeclaresConstructor(ConstructorDeclaration node) {
-    if (_enclosingClass.isMixin) {
-      _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, node.returnType);
-    }
-  }
-
   /**
    * Verify that the given mixin has the 'Object' superclass. The [mixinName] is
    * the node to report problem on. The [mixinElement] is the mixing to
@@ -4321,6 +4293,10 @@
       return;
     }
 
+    if (node.isLate) {
+      return;
+    }
+
     if (node.type == null) {
       return;
     }
@@ -4358,13 +4334,7 @@
     StaticWarningCode code = expression.staticType == _typeProvider.nullType
         ? StaticWarningCode.INVALID_USE_OF_NULL_VALUE
         : StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
-
-    if (expression is MethodInvocation) {
-      SimpleIdentifier methodName = expression.methodName;
-      _errorReporter.reportErrorForNode(code, methodName, []);
-    } else {
-      _errorReporter.reportErrorForNode(code, expression, []);
-    }
+    _errorReporter.reportErrorForNode(code, expression, []);
 
     return true;
   }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 2504097..8e6d623 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -5643,7 +5643,7 @@
 
   /// Create and return a new token with the given [type]. The token will
   /// replace the first portion of the given [token], so it will have the same
-  /// offset and will have any comments that might have preceeded the token.
+  /// offset and will have any comments that might have preceded the token.
   Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
     CommentToken comments = token.precedingComments;
     if (comments == null) {
@@ -7437,7 +7437,7 @@
       return null;
     }
     //
-    // We can't skip a type parameter because it can be preceeded by metadata,
+    // We can't skip a type parameter because it can be preceded by metadata,
     // so we just assume that everything before the matching end token is valid.
     //
     int depth = 1;
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index 5f560dd..e5b6f3d 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -132,7 +132,9 @@
       <ClassMember>[],
       null /* rightBracket */,
     );
-    currentToken = fastaParser.parseClassOrMixinMember(currentToken);
+    // TODO(danrubel): disambiguate between class and mixin
+    currentToken = fastaParser.parseClassMember(currentToken, className);
+    //currentToken = fastaParser.parseMixinMember(currentToken);
     ClassDeclaration declaration = astBuilder.classDeclaration;
     astBuilder.classDeclaration = null;
     return declaration.members.isNotEmpty ? declaration.members[0] : null;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 5d454a5..3f2e838 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -35,7 +34,6 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/static_type_analyzer.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/type_promotion_manager.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/variable_type_provider.dart';
@@ -73,10 +71,6 @@
   /// The type [Null].
   final InterfaceType _nullType;
 
-  /// The type Future<Null>, which is needed for determining whether it is safe
-  /// to have a bare "return;" in an async method.
-  final InterfaceType _futureNullType;
-
   /// The type system primitives
   final TypeSystem _typeSystem;
 
@@ -94,6 +88,9 @@
   /// The [LinterContext] used for possible const calculations.
   LinterContext _linterContext;
 
+  /// Is `true` if NNBD is enabled for the library being analyzed.
+  final bool _isNonNullable;
+
   /// Create a new instance of the [BestPracticesVerifier].
   ///
   /// @param errorReporter the error reporter
@@ -109,8 +106,8 @@
     DeclaredVariables declaredVariables,
     AnalysisOptions analysisOptions,
   })  : _nullType = typeProvider.nullType,
-        _futureNullType = typeProvider.futureNullType,
         _typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
+        _isNonNullable = unit.featureSet.isEnabled(Feature.non_nullable),
         _inheritanceManager = inheritanceManager,
         _invalidAccessVerifier =
             new _InvalidAccessVerifier(_errorReporter, _currentLibrary) {
@@ -133,8 +130,7 @@
 
   @override
   void visitAnnotation(Annotation node) {
-    ElementAnnotation element =
-        resolutionMap.elementAnnotationForAnnotation(node);
+    ElementAnnotation element = node.elementAnnotation;
     AstNode parent = node.parent;
     if (element?.isFactory == true) {
       if (parent is MethodDeclaration) {
@@ -261,7 +257,7 @@
 
   @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
-    if (resolutionMap.elementDeclaredByConstructorDeclaration(node).isFactory) {
+    if (node.declaredElement.isFactory) {
       if (node.body is BlockFunctionBody) {
         // Check the block for a return statement, if not, create the hint.
         if (!ExitDetector.exits(node.body)) {
@@ -576,8 +572,7 @@
       } else if (displayName == FunctionElement.CALL_METHOD_NAME &&
           node is MethodInvocation &&
           node.staticInvokeType is InterfaceType) {
-        DartType staticInvokeType =
-            resolutionMap.staticInvokeTypeForInvocationExpression(node);
+        DartType staticInvokeType = node.staticInvokeType;
         displayName = "${staticInvokeType.displayName}.${element.displayName}";
       }
       LibraryElement library =
@@ -921,6 +916,10 @@
 
   /// Produce several null-aware related hints.
   void _checkForNullAwareHints(Expression node, Token operator) {
+    if (_isNonNullable) {
+      return;
+    }
+
     if (operator == null || operator.type != TokenType.QUESTION_PERIOD) {
       return;
     }
@@ -1089,17 +1088,25 @@
     final requiredParameters =
         node.parameters.where((p) => p.declaredElement?.hasRequired == true);
     final nonNamedParamsWithRequired =
-        requiredParameters.where((p) => !p.isNamed);
+        requiredParameters.where((p) => p.isPositional);
     final namedParamsWithRequiredAndDefault = requiredParameters
         .where((p) => p.isNamed)
         .where((p) => p.declaredElement.defaultValueCode != null);
-    final paramsToHint = [
-      nonNamedParamsWithRequired,
-      namedParamsWithRequiredAndDefault
-    ].expand((e) => e);
-    for (final param in paramsToHint) {
+    for (final param in nonNamedParamsWithRequired.where((p) => p.isOptional)) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_REQUIRED_PARAM, param, [param.identifier.name]);
+          HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+          param,
+          [param.identifier.name]);
+    }
+    for (final param in nonNamedParamsWithRequired.where((p) => p.isRequired)) {
+      _errorReporter.reportErrorForNode(
+          HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
+          param,
+          [param.identifier.name]);
+    }
+    for (final param in namedParamsWithRequiredAndDefault) {
+      _errorReporter.reportErrorForNode(HintCode.INVALID_REQUIRED_NAMED_PARAM,
+          param, [param.identifier.name]);
     }
   }
 
@@ -1789,8 +1796,7 @@
 
   @override
   void visitCompilationUnit(CompilationUnit node) {
-    _enclosingLibrary =
-        resolutionMap.elementDeclaredByCompilationUnit(node).library;
+    _enclosingLibrary = node.declaredElement.library;
     for (Directive directive in node.directives) {
       directive.accept(this);
     }
@@ -1839,14 +1845,11 @@
           if (importedTime >= 0 &&
               importSourceKindMap[importedSource] != SourceKind.LIBRARY) {
             StringLiteral uriLiteral = node.uri;
-            ErrorCode errorCode = element.isDeferred
-                ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
-                : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
             errors.add(new AnalysisError(
                 _enclosingLibrary.source,
                 uriLiteral.offset,
                 uriLiteral.length,
-                errorCode,
+                CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
                 [uriLiteral.toSource()]));
           }
         }
@@ -2755,33 +2758,6 @@
   }
 }
 
-/// A type provider that returns non-nullable versions of the SDK types.
-class NonNullableTypeProvider extends TypeProviderImpl {
-  NonNullableTypeProvider(
-      LibraryElement coreLibrary, LibraryElement asyncLibrary)
-      : super(coreLibrary, asyncLibrary);
-
-  /// Return a type provider initialized from the same library elements as the
-  /// [baseProvider].
-  factory NonNullableTypeProvider.from(TypeProvider baseProvider) {
-    return NonNullableTypeProvider(baseProvider.boolType.element.library,
-        baseProvider.streamType.element.library);
-  }
-
-  @override
-  DartType get bottomType => BottomTypeImpl.instance;
-
-  @override
-  InterfaceType _getType(Namespace namespace, String typeName) {
-    InterfaceType type = super._getType(namespace, typeName);
-    if (type == null) {
-      return null;
-    }
-    return (type as TypeImpl).withNullability(NullabilitySuffix.none)
-        as InterfaceType;
-  }
-}
-
 /// Instances of the class `OverrideVerifier` visit all of the declarations in a
 /// compilation unit to verify that if they have an override annotation it is
 /// being used correctly.
@@ -2965,35 +2941,6 @@
   }
 }
 
-/// Kind of the redirecting constructor.
-class RedirectingConstructorKind
-    implements Comparable<RedirectingConstructorKind> {
-  static const RedirectingConstructorKind CONST =
-      const RedirectingConstructorKind('CONST', 0);
-
-  static const RedirectingConstructorKind NORMAL =
-      const RedirectingConstructorKind('NORMAL', 1);
-
-  static const List<RedirectingConstructorKind> values = const [CONST, NORMAL];
-
-  /// The name of this redirecting constructor kind.
-  final String name;
-
-  /// The ordinal value of the redirecting constructor kind.
-  final int ordinal;
-
-  const RedirectingConstructorKind(this.name, this.ordinal);
-
-  @override
-  int get hashCode => ordinal;
-
-  @override
-  int compareTo(RedirectingConstructorKind other) => ordinal - other.ordinal;
-
-  @override
-  String toString() => name;
-}
-
 /// The enumeration `ResolverErrorCode` defines the error codes used for errors
 /// detected by the resolver. The convention for this class is for the name of
 /// the error code to indicate the problem that caused the error to be generated
@@ -3707,8 +3654,7 @@
 
   @override
   void visitDefaultFormalParameter(DefaultFormalParameter node) {
-    InferenceContext.setType(node.defaultValue,
-        resolutionMap.elementDeclaredByFormalParameter(node.parameter)?.type);
+    InferenceContext.setType(node.defaultValue, node.declaredElement?.type);
     super.visitDefaultFormalParameter(node);
     ParameterElement element = node.declaredElement;
 
@@ -3736,7 +3682,7 @@
 
     _flowAnalysis?.flow?.doStatement_bodyBegin(
       node,
-      _flowAnalysis?.assignedVariables[node],
+      _flowAnalysis.assignedVariables.writtenInNode(node),
     );
     visitStatementInScope(body);
 
@@ -3893,8 +3839,8 @@
       iterable?.accept(this);
       _flowAnalysis?.loopVariable(loopVariable);
       loopVariable?.accept(this);
-      _flowAnalysis?.flow
-          ?.forEach_bodyBegin(_flowAnalysis?.assignedVariables[node]);
+      _flowAnalysis?.flow?.forEach_bodyBegin(
+          _flowAnalysis.assignedVariables.writtenInNode(node));
       node.body?.accept(this);
       _flowAnalysis?.flow?.forEach_end();
 
@@ -3971,7 +3917,7 @@
       loopVariable?.accept(this);
 
       _flowAnalysis?.flow?.forEach_bodyBegin(
-        _flowAnalysis?.assignedVariables[node],
+        _flowAnalysis.assignedVariables.writtenInNode(node),
       );
 
       Statement body = node.body;
@@ -4317,8 +4263,7 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
-    InferenceContext.setType(node.argumentList,
-        resolutionMap.staticElementForConstructorReference(node)?.type);
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     node.argumentList?.accept(this);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -4426,8 +4371,7 @@
     // because it needs to be visited in the context of the constructor
     // invocation.
     //
-    InferenceContext.setType(node.argumentList,
-        resolutionMap.staticElementForConstructorReference(node)?.type);
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     node.argumentList?.accept(this);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -4454,7 +4398,8 @@
 
       if (_flowAnalysis != null) {
         var flow = _flowAnalysis.flow;
-        var assignedInCases = _flowAnalysis.assignedVariables[node];
+        var assignedInCases =
+            _flowAnalysis.assignedVariables.writtenInNode(node);
 
         flow.switchStatement_expressionEnd(node);
 
@@ -4462,20 +4407,17 @@
         var members = node.members;
         for (var member in members) {
           flow.switchStatement_beginCase(
-            member.labels.isNotEmpty
-                ? assignedInCases
-                : _flowAnalysis.assignedVariables.emptySet,
+            member.labels.isNotEmpty,
+            assignedInCases,
           );
           member.accept(this);
 
-          // Implicit `break` at the end of `default`.
           if (member is SwitchDefault) {
             hasDefault = true;
-            flow.handleBreak(node);
           }
         }
 
-        flow.switchStatement_end(node, hasDefault);
+        flow.switchStatement_end(hasDefault);
       } else {
         node.members.accept(this);
       }
@@ -4510,7 +4452,7 @@
     flow.tryCatchStatement_bodyBegin();
     body.accept(this);
     flow.tryCatchStatement_bodyEnd(
-      _flowAnalysis.assignedVariables[body],
+      _flowAnalysis.assignedVariables.writtenInNode(body),
     );
 
     var catchLength = catchClauses.length;
@@ -4531,11 +4473,11 @@
 
     if (finallyBlock != null) {
       flow.tryFinallyStatement_finallyBegin(
-        _flowAnalysis.assignedVariables[body],
+        _flowAnalysis.assignedVariables.writtenInNode(body),
       );
       finallyBlock.accept(this);
       flow.tryFinallyStatement_end(
-        _flowAnalysis.assignedVariables[finallyBlock],
+        _flowAnalysis.assignedVariables.writtenInNode(finallyBlock),
       );
     }
   }
@@ -4566,8 +4508,7 @@
   void visitVariableDeclarationList(VariableDeclarationList node) {
     _flowAnalysis?.variableDeclarationList(node);
     for (VariableDeclaration decl in node.variables) {
-      VariableElement variableElement =
-          resolutionMap.elementDeclaredByVariableDeclaration(decl);
+      VariableElement variableElement = decl.declaredElement;
       InferenceContext.setType(decl, variableElement?.type);
     }
     super.visitVariableDeclarationList(node);
@@ -4587,7 +4528,7 @@
       InferenceContext.setType(condition, typeProvider.boolType);
 
       _flowAnalysis?.flow?.whileStatement_conditionBegin(
-        _flowAnalysis?.assignedVariables[node],
+        _flowAnalysis.assignedVariables.writtenInNode(node),
       );
       condition?.accept(this);
 
@@ -4849,8 +4790,7 @@
       return;
     }
 
-    ConstructorElement originalElement =
-        resolutionMap.staticElementForConstructorReference(constructor);
+    ConstructorElement originalElement = constructor.staticElement;
     FunctionType inferred;
     // If the constructor is generic, we'll have a ConstructorMember that
     // substitutes in type arguments (possibly `dynamic`) from earlier in
@@ -4987,16 +4927,13 @@
   /// An error will be reported to [onError] if any of the arguments cannot be
   /// matched to a parameter. onError can be null to ignore the error.
   ///
-  /// The flag [reportAsError] should be `true` if a compile-time error should
-  /// be reported; or `false` if a compile-time warning should be reported.
-  ///
   /// Returns the parameters that correspond to the arguments. If no parameter
   /// matched an argument, that position will be `null` in the list.
   static List<ParameterElement> resolveArgumentsToParameters(
       ArgumentList argumentList,
       List<ParameterElement> parameters,
-      void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
-      {bool reportAsError: false}) {
+      void onError(ErrorCode errorCode, AstNode node,
+          [List<Object> arguments])) {
     if (parameters.isEmpty && argumentList.arguments.isEmpty) {
       return const <ParameterElement>[];
     }
@@ -5035,11 +4972,9 @@
         ParameterElement element =
             namedParameters != null ? namedParameters[name] : null;
         if (element == null) {
-          ErrorCode errorCode = (reportAsError
-              ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
-              : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
           if (onError != null) {
-            onError(errorCode, nameNode, [name]);
+            onError(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, nameNode,
+                [name]);
           }
         } else {
           resolvedParameters[i] = element;
@@ -5063,12 +4998,9 @@
       }
     }
     if (positionalArgumentCount < requiredParameterCount && noBlankArguments) {
-      ErrorCode errorCode = (reportAsError
-          ? CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS
-          : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
       if (onError != null) {
-        onError(errorCode, argumentList,
-            [requiredParameterCount, positionalArgumentCount]);
+        onError(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS,
+            argumentList, [requiredParameterCount, positionalArgumentCount]);
       }
     } else if (positionalArgumentCount > unnamedParameterCount &&
         noBlankArguments) {
@@ -5076,13 +5008,10 @@
       int namedParameterCount = namedParameters?.length ?? 0;
       int namedArgumentCount = usedNames?.length ?? 0;
       if (namedParameterCount > namedArgumentCount) {
-        errorCode = (reportAsError
-            ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED
-            : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED);
+        errorCode =
+            CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED;
       } else {
-        errorCode = (reportAsError
-            ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
-            : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
+        errorCode = CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS;
       }
       if (onError != null) {
         onError(errorCode, argumentList,
@@ -6040,7 +5969,6 @@
       // identifier being used as a class name.
       // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
       SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
-      RedirectingConstructorKind redirectingConstructorKind;
       if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
         reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
             typeName, [typeName.name]);
@@ -6056,14 +5984,9 @@
       } else if (_isTypeNameInIsExpression(node)) {
         reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
             typeName, [typeName.name]);
-      } else if ((redirectingConstructorKind =
-              _getRedirectingConstructorKind(node)) !=
-          null) {
-        ErrorCode errorCode =
-            (redirectingConstructorKind == RedirectingConstructorKind.CONST
-                ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
-                : StaticWarningCode.REDIRECT_TO_NON_CLASS);
-        reportErrorForNode(errorCode, typeName, [typeName.name]);
+      } else if (_isRedirectingConstructor(node)) {
+        reportErrorForNode(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, typeName,
+            [typeName.name]);
       } else if (_isTypeNameInTypeArgumentList(node)) {
         reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
             typeName, [typeName.name]);
@@ -6114,11 +6037,11 @@
           }
         } else {
           reportErrorForNode(
-              StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+              CompileTimeErrorCode.UNDEFINED_CLASS, typeName, [typeName.name]);
         }
       } else {
         reportErrorForNode(
-            StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+            CompileTimeErrorCode.UNDEFINED_CLASS, typeName, [typeName.name]);
       }
     }
     if (!elementValid) {
@@ -6153,7 +6076,6 @@
       type = _getTypeWhenMultiplyDefined(elements) as TypeImpl;
     } else {
       // The name does not represent a type.
-      RedirectingConstructorKind redirectingConstructorKind;
       if (_isTypeNameInCatchClause(node)) {
         reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
             [typeName.name]);
@@ -6163,14 +6085,9 @@
       } else if (_isTypeNameInIsExpression(node)) {
         reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
             [typeName.name]);
-      } else if ((redirectingConstructorKind =
-              _getRedirectingConstructorKind(node)) !=
-          null) {
-        ErrorCode errorCode =
-            (redirectingConstructorKind == RedirectingConstructorKind.CONST
-                ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
-                : StaticWarningCode.REDIRECT_TO_NON_CLASS);
-        reportErrorForNode(errorCode, typeName, [typeName.name]);
+      } else if (_isRedirectingConstructor(node)) {
+        reportErrorForNode(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, typeName,
+            [typeName.name]);
       } else if (_isTypeNameInTypeArgumentList(node)) {
         reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
             typeName, [typeName.name]);
@@ -6282,23 +6199,6 @@
     return nullability;
   }
 
-  /// Checks if the given [typeName] is the target in a redirected constructor.
-  RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
-    AstNode parent = typeName.parent;
-    if (parent is ConstructorName) {
-      AstNode grandParent = parent.parent;
-      if (grandParent is ConstructorDeclaration) {
-        if (identical(grandParent.redirectedConstructor, parent)) {
-          if (grandParent.constKeyword != null) {
-            return RedirectingConstructorKind.CONST;
-          }
-          return RedirectingConstructorKind.NORMAL;
-        }
-      }
-    }
-    return null;
-  }
-
   /// Return the type represented by the given type [annotation].
   DartType _getType(TypeAnnotation annotation) {
     DartType type = annotation.type;
@@ -6378,6 +6278,21 @@
     return null;
   }
 
+  /// Return `true` if the given [typeName] is the target in a redirected
+  /// constructor.
+  bool _isRedirectingConstructor(TypeName typeName) {
+    AstNode parent = typeName.parent;
+    if (parent is ConstructorName) {
+      AstNode grandParent = parent.parent;
+      if (grandParent is ConstructorDeclaration) {
+        if (identical(grandParent.redirectedConstructor, parent)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /// Checks if the given [typeName] is used as the type in an as expression.
   bool _isTypeNameInAsExpression(TypeName typeName) {
     AstNode parent = typeName.parent;
@@ -6792,301 +6707,6 @@
   bool isObjectMethod(String id);
 }
 
-/// Provide common functionality shared by the various TypeProvider
-/// implementations.
-abstract class TypeProviderBase implements TypeProvider {
-  @override
-  List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
-        boolType,
-        doubleType,
-        intType,
-        nullType,
-        numType,
-        stringType
-      ];
-
-  @override
-  bool isObjectGetter(String id) {
-    PropertyAccessorElement element = objectType.element.getGetter(id);
-    return (element != null && !element.isStatic);
-  }
-
-  @override
-  bool isObjectMember(String id) {
-    return isObjectGetter(id) || isObjectMethod(id);
-  }
-
-  @override
-  bool isObjectMethod(String id) {
-    MethodElement element = objectType.element.getMethod(id);
-    return (element != null && !element.isStatic);
-  }
-}
-
-/// Instances of the class `TypeProviderImpl` provide access to types defined by
-/// the language by looking for those types in the element model for the core
-/// library.
-class TypeProviderImpl extends TypeProviderBase {
-  /// The type representing the built-in type 'bool'.
-  InterfaceType _boolType;
-
-  /// The type representing the built-in type 'double'.
-  InterfaceType _doubleType;
-
-  /// The type representing the built-in type 'Deprecated'.
-  InterfaceType _deprecatedType;
-
-  /// The type representing the built-in type 'Function'.
-  InterfaceType _functionType;
-
-  /// The type representing 'Future<dynamic>'.
-  InterfaceType _futureDynamicType;
-
-  /// The type representing 'Future<Null>'.
-  InterfaceType _futureNullType;
-
-  /// The type representing 'FutureOr<Null>'.
-  InterfaceType _futureOrNullType;
-
-  /// The type representing the built-in type 'FutureOr'.
-  InterfaceType _futureOrType;
-
-  /// The type representing the built-in type 'Future'.
-  InterfaceType _futureType;
-
-  /// The type representing the built-in type 'int'.
-  InterfaceType _intType;
-
-  /// The type representing 'Iterable<dynamic>'.
-  InterfaceType _iterableDynamicType;
-
-  /// The type representing 'Iterable<Object>'.
-  InterfaceType _iterableObjectType;
-
-  /// The type representing the built-in type 'Iterable'.
-  InterfaceType _iterableType;
-
-  /// The type representing the built-in type 'List'.
-  InterfaceType _listType;
-
-  /// The type representing the built-in type 'Map'.
-  InterfaceType _mapType;
-
-  /// The type representing the built-in type 'Map<Object, Object>'.
-  InterfaceType _mapObjectObjectType;
-
-  /// An shared object representing the value 'null'.
-  DartObjectImpl _nullObject;
-
-  /// The type representing the type 'Null'.
-  InterfaceType _nullType;
-
-  /// The type representing the built-in type 'num'.
-  InterfaceType _numType;
-
-  /// The type representing the built-in type 'Object'.
-  InterfaceType _objectType;
-
-  /// The type representing the type 'Set'.
-  InterfaceType _setType;
-
-  /// The type representing the built-in type 'StackTrace'.
-  InterfaceType _stackTraceType;
-
-  /// The type representing 'Stream<dynamic>'.
-  InterfaceType _streamDynamicType;
-
-  /// The type representing the built-in type 'Stream'.
-  InterfaceType _streamType;
-
-  /// The type representing the built-in type 'String'.
-  InterfaceType _stringType;
-
-  /// The type representing the built-in type 'Symbol'.
-  InterfaceType _symbolType;
-
-  /// The type representing the built-in type 'Type'.
-  InterfaceType _typeType;
-
-  /// Initialize a newly created type provider to provide the types defined in
-  /// the given [coreLibrary] and [asyncLibrary].
-  TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
-    _initializeFrom(coreLibrary, asyncLibrary);
-  }
-
-  /// Return a type provider initialized from the same library elements as the
-  /// [baseProvider].
-  factory TypeProviderImpl.from(TypeProvider baseProvider) {
-    return TypeProviderImpl(baseProvider.boolType.element.library,
-        baseProvider.streamType.element.library);
-  }
-
-  @override
-  InterfaceType get boolType => _boolType;
-
-  @override
-  DartType get bottomType => BottomTypeImpl.instanceLegacy;
-
-  @override
-  InterfaceType get deprecatedType => _deprecatedType;
-
-  @override
-  InterfaceType get doubleType => _doubleType;
-
-  @override
-  DartType get dynamicType => DynamicTypeImpl.instance;
-
-  @override
-  InterfaceType get functionType => _functionType;
-
-  @override
-  InterfaceType get futureDynamicType => _futureDynamicType;
-
-  @override
-  InterfaceType get futureNullType => _futureNullType;
-
-  @override
-  InterfaceType get futureOrNullType => _futureOrNullType;
-
-  @override
-  InterfaceType get futureOrType => _futureOrType;
-
-  @override
-  InterfaceType get futureType => _futureType;
-
-  @override
-  InterfaceType get intType => _intType;
-
-  @override
-  InterfaceType get iterableDynamicType => _iterableDynamicType;
-
-  @override
-  InterfaceType get iterableObjectType => _iterableObjectType;
-
-  @override
-  InterfaceType get iterableType => _iterableType;
-
-  @override
-  InterfaceType get listType => _listType;
-
-  @override
-  InterfaceType get mapObjectObjectType => _mapObjectObjectType;
-
-  @override
-  InterfaceType get mapType => _mapType;
-
-  @override
-  DartType get neverType => BottomTypeImpl.instance;
-
-  @override
-  DartObjectImpl get nullObject {
-    if (_nullObject == null) {
-      _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
-    }
-    return _nullObject;
-  }
-
-  @override
-  InterfaceType get nullType => _nullType;
-
-  @override
-  InterfaceType get numType => _numType;
-
-  @override
-  InterfaceType get objectType => _objectType;
-
-  @override
-  InterfaceType get setType => _setType;
-
-  @override
-  InterfaceType get stackTraceType => _stackTraceType;
-
-  @override
-  InterfaceType get streamDynamicType => _streamDynamicType;
-
-  @override
-  InterfaceType get streamType => _streamType;
-
-  @override
-  InterfaceType get stringType => _stringType;
-
-  @override
-  InterfaceType get symbolType => _symbolType;
-
-  @override
-  InterfaceType get typeType => _typeType;
-
-  @override
-  VoidType get voidType => VoidTypeImpl.instance;
-
-  /// Return the type with the given [typeName] from the given [namespace], or
-  /// `null` if there is no class with the given name.
-  InterfaceType _getType(Namespace namespace, String typeName) {
-    Element element = namespace.get(typeName);
-    if (element == null) {
-      AnalysisEngine.instance.logger
-          .logInformation("No definition of type $typeName");
-      return null;
-    }
-    return (element as ClassElement).type;
-  }
-
-  /// Initialize the types provided by this type provider from the given
-  /// [Namespace]s.
-  void _initializeFrom(
-      LibraryElement coreLibrary, LibraryElement asyncLibrary) {
-    Namespace coreNamespace =
-        new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
-    Namespace asyncNamespace =
-        new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
-
-    _boolType = _getType(coreNamespace, 'bool');
-    _deprecatedType = _getType(coreNamespace, 'Deprecated');
-    _doubleType = _getType(coreNamespace, 'double');
-    _functionType = _getType(coreNamespace, 'Function');
-    _futureOrType = _getType(asyncNamespace, 'FutureOr');
-    _futureType = _getType(asyncNamespace, 'Future');
-    _intType = _getType(coreNamespace, 'int');
-    _iterableType = _getType(coreNamespace, 'Iterable');
-    _listType = _getType(coreNamespace, 'List');
-    _mapType = _getType(coreNamespace, 'Map');
-    _nullType = _getType(coreNamespace, 'Null');
-    _numType = _getType(coreNamespace, 'num');
-    _objectType = _getType(coreNamespace, 'Object');
-    _setType = _getType(coreNamespace, 'Set');
-    _stackTraceType = _getType(coreNamespace, 'StackTrace');
-    _streamType = _getType(asyncNamespace, 'Stream');
-    _stringType = _getType(coreNamespace, 'String');
-    _symbolType = _getType(coreNamespace, 'Symbol');
-    _typeType = _getType(coreNamespace, 'Type');
-    _futureDynamicType = _futureType.instantiate(<DartType>[dynamicType]);
-    _futureNullType = _futureType.instantiate(<DartType>[_nullType]);
-    _iterableDynamicType = _iterableType.instantiate(<DartType>[dynamicType]);
-    _iterableObjectType = _iterableType.instantiate(<DartType>[_objectType]);
-    _mapObjectObjectType =
-        _mapType.instantiate(<DartType>[_objectType, _objectType]);
-    _streamDynamicType = _streamType.instantiate(<DartType>[dynamicType]);
-    // FutureOr<T> is still fairly new, so if we're analyzing an SDK that
-    // doesn't have it yet, create an element for it.
-    _futureOrType ??= createPlaceholderFutureOr(_futureType, _objectType);
-    _futureOrNullType = _futureOrType.instantiate(<DartType>[_nullType]);
-  }
-
-  /// Create an [InterfaceType] that can be used for `FutureOr<T>` if the SDK
-  /// being analyzed does not contain its own `FutureOr<T>`.  This ensures that
-  /// we can analyze older SDKs.
-  static InterfaceType createPlaceholderFutureOr(
-      InterfaceType futureType, InterfaceType objectType) {
-    // TODO(brianwilkerson) Remove this method now that the class has been
-    //  defined.
-    var compilationUnit =
-        futureType.element.getAncestor((e) => e is CompilationUnitElement);
-    var element = ElementFactory.classElement('FutureOr', objectType, ['T']);
-    element.enclosingElement = compilationUnit;
-    return element.type;
-  }
-}
-
 /// Modes in which [TypeResolverVisitor] works.
 enum TypeResolverMode {
   /// Resolve all names types of all nodes.
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 73b881c..3a98084 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -323,16 +322,28 @@
         operator == TokenType.BAR_BAR_EQ) {
       _recordStaticType(node, _nonNullable(_typeProvider.boolType));
     } else {
-      ExecutableElement staticMethodElement = node.staticElement;
-      DartType staticType = _computeStaticReturnType(staticMethodElement);
-      staticType = _typeSystem.refineBinaryExpressionType(
-          _getStaticType(node.leftHandSide, read: true),
-          operator,
-          node.rightHandSide.staticType,
-          staticType,
-          _featureSet);
-      _recordStaticType(node, staticType);
+      var operatorElement = node.staticElement;
+      var type = operatorElement?.returnType ?? _dynamicType;
+      type = _typeSystem.refineBinaryExpressionType(
+        _getStaticType(node.leftHandSide, read: true),
+        operator,
+        node.rightHandSide.staticType,
+        type,
+        _featureSet,
+      );
+      _recordStaticType(node, type);
+
+      var leftWriteType = _getStaticType(node.leftHandSide);
+      if (!_typeSystem.isAssignableTo(type, leftWriteType,
+          featureSet: _featureSet)) {
+        _resolver.errorReporter.reportTypeErrorForNode(
+          StaticTypeWarningCode.INVALID_ASSIGNMENT,
+          node.rightHandSide,
+          [type, leftWriteType],
+        );
+      }
     }
+    _nullShortingTermination(node);
   }
 
   /**
@@ -594,15 +605,20 @@
    */
   @override
   void visitIndexExpression(IndexExpression node) {
+    DartType type;
     if (node.inSetterContext()) {
-      ExecutableElement staticMethodElement = node.staticElement;
-      DartType staticType = _computeArgumentType(staticMethodElement);
-      _recordStaticType(node, staticType);
+      var parameters = node.staticElement?.parameters;
+      if (parameters?.length == 2) {
+        type = parameters[1].type;
+      }
     } else {
-      ExecutableElement staticMethodElement = node.staticElement;
-      DartType staticType = _computeStaticReturnType(staticMethodElement);
-      _recordStaticType(node, staticType);
+      type = node.staticElement?.returnType;
     }
+
+    type ??= _dynamicType;
+
+    _recordStaticType(node, type);
+    _nullShortingTermination(node);
   }
 
   /**
@@ -839,6 +855,12 @@
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     SimpleIdentifier prefixedIdentifier = node.identifier;
     Element staticElement = prefixedIdentifier.staticElement;
+
+    if (staticElement is ExtensionElement) {
+      _setExtensionIdentifierType(node);
+      return;
+    }
+
     DartType staticType = _dynamicType;
     if (staticElement is ClassElement) {
       if (_isNotTypeLiteral(node)) {
@@ -953,15 +975,12 @@
       // TODO(brianwilkerson) Report this internal error.
     }
 
-    if (node.operator.type == TokenType.QUESTION_PERIOD &&
-        _nonNullableEnabled) {
-      staticType = _typeSystem.makeNullable(staticType);
-    }
     staticType = _inferTearOff(node, node.propertyName, staticType);
 
     if (!_inferObjectAccess(node, staticType, propertyName)) {
       _recordStaticType(propertyName, staticType);
       _recordStaticType(node, staticType);
+      _nullShortingTermination(node);
     }
   }
 
@@ -1072,6 +1091,12 @@
   @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
     Element element = node.staticElement;
+
+    if (element is ExtensionElement) {
+      _setExtensionIdentifierType(node);
+      return;
+    }
+
     DartType staticType = _dynamicType;
     if (element is ClassElement) {
       if (_isNotTypeLiteral(node)) {
@@ -1131,7 +1156,8 @@
 
   @override
   void visitSuperExpression(SuperExpression node) {
-    if (thisType == null) {
+    if (thisType == null ||
+        node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
       // TODO(brianwilkerson) Report this error if it hasn't already been
       // reported.
       _recordStaticType(node, _dynamicType);
@@ -1225,22 +1251,6 @@
     }
   }
 
-  /**
-   * Record that the static type of the given node is the type of the second argument to the method
-   * represented by the given element.
-   *
-   * @param element the element representing the method invoked by the given node
-   */
-  DartType _computeArgumentType(ExecutableElement element) {
-    if (element != null) {
-      List<ParameterElement> parameters = element.parameters;
-      if (parameters != null && parameters.length == 2) {
-        return parameters[1].type;
-      }
-    }
-    return _dynamicType;
-  }
-
   DartType _computeElementType(CollectionElement element) {
     if (element is ForElement) {
       return _computeElementType(element.body);
@@ -1268,9 +1278,7 @@
         }
       } else if (expressionType.isDynamic) {
         return expressionType;
-      } else if (isNull &&
-          element.spreadOperator.type ==
-              TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+      } else if (isNull && element.isNullAware) {
         return expressionType;
       }
       // TODO(brianwilkerson) Report this as an error.
@@ -1538,9 +1546,7 @@
             elementType: expressionType,
             keyType: expressionType,
             valueType: expressionType);
-      } else if (isNull &&
-          element.spreadOperator.type ==
-              TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+      } else if (isNull && element.isNullAware) {
         return _InferredCollectionElementTypeInformation(
             elementType: expressionType,
             keyType: expressionType,
@@ -1764,7 +1770,7 @@
     AstNode parent = node.parent;
     if (initializer != null) {
       if (parent is VariableDeclarationList && parent.type == null) {
-        DartType type = resolutionMap.staticTypeForExpression(initializer);
+        DartType type = initializer.staticType;
         if (type != null && !type.isBottom && !type.isDartCoreNull) {
           VariableElement element = node.declaredElement;
           if (element is LocalVariableElementImpl) {
@@ -2002,6 +2008,25 @@
     return type;
   }
 
+  /// If we reached a null-shorting termination, and the [node] has null
+  /// shorting, make the type of the [node] nullable.
+  void _nullShortingTermination(Expression node) {
+    if (!_nonNullableEnabled) return;
+
+    var parent = node.parent;
+    if (parent is AssignmentExpression && parent.leftHandSide == node) {
+      return;
+    }
+    if (parent is PropertyAccess) {
+      return;
+    }
+
+    if (_hasNullShorting(node)) {
+      var type = node.staticType;
+      node.staticType = _typeSystem.makeNullable(type);
+    }
+  }
+
   /**
    * Record that the static type of the given node is the given type.
    *
@@ -2016,6 +2041,40 @@
     }
   }
 
+  void _setExtensionIdentifierType(Identifier node) {
+    if (node is SimpleIdentifier && node.inDeclarationContext()) {
+      return;
+    }
+
+    var parent = node.parent;
+
+    if (parent is PrefixedIdentifier && parent.identifier == node) {
+      node = parent;
+      parent = node.parent;
+    }
+
+    if (parent is CommentReference ||
+        parent is ExtensionOverride && parent.extensionName == node ||
+        parent is MethodInvocation && parent.target == node ||
+        parent is PrefixedIdentifier && parent.prefix == node ||
+        parent is PropertyAccess && parent.target == node) {
+      return;
+    }
+
+    _resolver.errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
+      node,
+      [node.name],
+    );
+
+    if (node is PrefixedIdentifier) {
+      node.identifier.staticType = _dynamicType;
+      node.staticType = _dynamicType;
+    } else if (node is SimpleIdentifier) {
+      node.staticType = _dynamicType;
+    }
+  }
+
   DartType _toMapType(SetOrMapLiteral node, DartType contextType,
       List<_InferredCollectionElementTypeInformation> inferredTypes) {
     DartType dynamicType = _typeProvider.dynamicType;
@@ -2116,6 +2175,23 @@
       return type;
     }
   }
+
+  /// Return `true` if the [node] has null-aware shorting, e.g. `foo?.bar`.
+  static bool _hasNullShorting(Expression node) {
+    if (node is AssignmentExpression) {
+      return _hasNullShorting(node.leftHandSide);
+    }
+    if (node is IndexExpression) {
+      return node.leftBracket.type ==
+              TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET ||
+          _hasNullShorting(node.target);
+    }
+    if (node is PropertyAccess) {
+      return node.operator.type == TokenType.QUESTION_PERIOD ||
+          _hasNullShorting(node.target);
+    }
+    return false;
+  }
 }
 
 class _InferredCollectionElementTypeInformation {
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 8627558..5d27b81 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -2,797 +2,61 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '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/type.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart' show Source;
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/string_source.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk_elements.dart';
 
 /**
  * A type provider that can be used by tests without creating the element model
  * for the core library.
  */
-class TestTypeProvider extends TypeProviderBase {
-  final bool _isNonNullableByDefault;
+class TestTypeProvider extends TypeProviderImpl {
+  factory TestTypeProvider([
+    AnalysisContext context,
+    Object analysisDriver,
+    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+  ]) {
+    context ??= _MockAnalysisContext();
+    var sdkElements = MockSdkElements(context, nullabilitySuffix);
+    return TestTypeProvider._(
+      sdkElements.coreLibrary,
+      sdkElements.asyncLibrary,
+    );
+  }
 
-  /**
-   * The type representing the built-in type 'bool'.
-   */
-  InterfaceType _boolType;
+  TestTypeProvider._(LibraryElement coreLibrary, LibraryElement asyncLibrary)
+      : super(coreLibrary, asyncLibrary);
+}
 
-  /**
-   * The type representing the type 'bottom'.
-   */
-  DartType _bottomType;
+class _MockAnalysisContext implements AnalysisContext {
+  @override
+  final SourceFactory sourceFactory = _MockSourceFactory();
 
-  /**
-   * The type representing the built-in type 'double'.
-   */
-  InterfaceType _doubleType;
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
 
-  /**
-   * The type representing the built-in type 'deprecated'.
-   */
-  InterfaceType _deprecatedType;
+class _MockSource implements Source {
+  @override
+  final Uri uri;
 
-  /**
-   * The type representing the built-in type 'dynamic'.
-   */
-  DartType _dynamicType;
-
-  /**
-   * The type representing the built-in type 'Function'.
-   */
-  InterfaceType _functionType;
-
-  /**
-   * The type representing 'Future<dynamic>'
-   */
-  InterfaceType _futureDynamicType;
-
-  /**
-   * The type representing 'Future<Null>'
-   */
-  InterfaceType _futureNullType;
-
-  /**
-   * The type representing the built-in type 'FutureOr'
-   */
-  InterfaceType _futureOrNullType;
-
-  /**
-   * The type representing the built-in type 'FutureOr'
-   */
-  InterfaceType _futureOrType;
-
-  /**
-   * The type representing the built-in type 'Future'
-   */
-  InterfaceType _futureType;
-
-  /**
-   * The type representing the built-in type 'int'.
-   */
-  InterfaceType _intType;
-
-  /**
-   * The type representing 'Iterable<dynamic>'
-   */
-  InterfaceType _iterableDynamicType;
-
-  /**
-   * The type representing 'Iterable<Object>'
-   */
-  InterfaceType _iterableObjectType;
-
-  /**
-   * The type representing the built-in type 'Iterable'.
-   */
-  InterfaceType _iterableType;
-
-  /**
-   * The type representing the built-in type 'Iterator'.
-   */
-  InterfaceType _iteratorType;
-
-  /**
-   * The type representing the built-in type 'List'.
-   */
-  InterfaceType _listType;
-
-  /**
-   * The type representing the built-in type 'Map'.
-   */
-  InterfaceType _mapType;
-
-  /**
-   * The type representing the built-in type 'Map<Object, Object>'.
-   */
-  InterfaceType _mapObjectObjectType;
-
-  /**
-   * An shared object representing the value 'null'.
-   */
-  DartObjectImpl _nullObject;
-
-  /**
-   * The type representing the built-in type 'Null'.
-   */
-  InterfaceType _nullType;
-
-  /**
-   * The type representing the built-in type 'num'.
-   */
-  InterfaceType _numType;
-
-  /**
-   * The type representing the built-in type 'Object'.
-   */
-  InterfaceType _objectType;
-
-  /**
-   * The type representing the built-in type 'Set'.
-   */
-  InterfaceType _setType;
-
-  /**
-   * The type representing the built-in type 'StackTrace'.
-   */
-  InterfaceType _stackTraceType;
-
-  /**
-   * The type representing 'Stream<dynamic>'.
-   */
-  InterfaceType _streamDynamicType;
-
-  /**
-   * The type representing the built-in type 'Stream'.
-   */
-  InterfaceType _streamType;
-
-  /**
-   * The type representing the built-in type 'String'.
-   */
-  InterfaceType _stringType;
-
-  /**
-   * The type representing the built-in type 'Symbol'.
-   */
-  InterfaceType _symbolType;
-
-  /**
-   * The type representing the built-in type 'Type'.
-   */
-  InterfaceType _typeType;
-
-  /**
-   * The analysis context, if any. Used to create an appropriate 'dart:async'
-   * library to back `Future<T>`.
-   */
-  AnalysisContext _context;
-
-  /**
-   * The analysis driver, if any. Used to create an appropriate 'dart:async'
-   * library to back `Future<T>`.
-   */
-  AnalysisDriver _driver;
-
-  /// TODO(paulberry): rework API and make _isNonNullableByDefault required.
-  TestTypeProvider(
-      [this._context, this._driver, this._isNonNullableByDefault = false]);
+  _MockSource(this.uri);
 
   @override
-  InterfaceType get boolType {
-    if (_boolType == null) {
-      ClassElementImpl boolElement = ElementFactory.classElement2("bool");
-      _boolType = boolElement.type;
-      ConstructorElementImpl fromEnvironment =
-          ElementFactory.constructorElement(
-              boolElement, "fromEnvironment", true);
-      fromEnvironment.parameters = <ParameterElement>[
-        ElementFactory.requiredParameter2("name", stringType),
-        ElementFactory.namedParameter3("defaultValue",
-            type: _boolType,
-            initializer: AstTestFactory.booleanLiteral(false),
-            initializerCode: 'false')
-      ];
-      fromEnvironment.factory = true;
-      fromEnvironment.isCycleFree = true;
-      boolElement.constructors = <ConstructorElement>[fromEnvironment];
-    }
-    return _boolType;
-  }
+  String get encoding => '$uri';
 
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSourceFactory implements SourceFactory {
   @override
-  DartType get bottomType {
-    if (_bottomType == null) {
-      _bottomType = BottomTypeImpl.instance;
-    }
-    return _bottomType;
+  Source forUri(String uriStr) {
+    var uri = Uri.parse(uriStr);
+    return _MockSource(uri);
   }
 
-  @override
-  InterfaceType get deprecatedType {
-    if (_deprecatedType == null) {
-      ClassElementImpl deprecatedElement =
-          ElementFactory.classElement2("Deprecated");
-      FieldElementImpl expiresField = ElementFactory.fieldElement(
-          'expires', false, true, false, stringType);
-      deprecatedElement.fields = <FieldElement>[expiresField];
-      deprecatedElement.accessors = <PropertyAccessorElement>[
-        expiresField.getter
-      ];
-      ConstructorElementImpl constructor = ElementFactory.constructorElement(
-          deprecatedElement, '', true, [stringType]);
-      (constructor.parameters[0] as ParameterElementImpl).name = 'expires';
-      ConstructorFieldInitializer expiresInit =
-          AstTestFactory.constructorFieldInitializer(
-              true, 'expires', AstTestFactory.identifier3('expires'));
-      expiresInit.fieldName.staticElement = expiresField;
-      (expiresInit.expression as SimpleIdentifier).staticElement =
-          constructor.parameters[0];
-      constructor.constantInitializers = <ConstructorInitializer>[expiresInit];
-      deprecatedElement.constructors = <ConstructorElement>[constructor];
-      _deprecatedType = deprecatedElement.type;
-    }
-    return _deprecatedType;
-  }
-
-  @override
-  InterfaceType get doubleType {
-    if (_doubleType == null) {
-      _initializeNumericTypes();
-    }
-    return _doubleType;
-  }
-
-  @override
-  DartType get dynamicType {
-    if (_dynamicType == null) {
-      _dynamicType = DynamicTypeImpl.instance;
-    }
-    return _dynamicType;
-  }
-
-  @override
-  InterfaceType get functionType {
-    if (_functionType == null) {
-      ClassElementImpl functionClass = ElementFactory.classElement2("Function");
-      functionClass.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(functionClass, null, false)
-      ];
-      _functionType = functionClass.type;
-    }
-    return _functionType;
-  }
-
-  @override
-  InterfaceType get futureDynamicType {
-    if (_futureDynamicType == null) {
-      _futureDynamicType = futureType.instantiate(<DartType>[dynamicType]);
-    }
-    return _futureDynamicType;
-  }
-
-  @override
-  InterfaceType get futureNullType {
-    if (_futureNullType == null) {
-      _futureNullType = futureType.instantiate(<DartType>[nullType]);
-    }
-    return _futureNullType;
-  }
-
-  @override
-  InterfaceType get futureOrNullType {
-    if (_futureOrNullType == null) {
-      _futureOrNullType = futureOrType.instantiate(<DartType>[nullType]);
-    }
-    return _futureOrNullType;
-  }
-
-  @override
-  InterfaceType get futureOrType {
-    if (_futureOrType == null) {
-      _initDartAsync();
-    }
-    return _futureOrType;
-  }
-
-  @override
-  InterfaceType get futureType {
-    if (_futureType == null) {
-      _initDartAsync();
-    }
-    return _futureType;
-  }
-
-  @override
-  InterfaceType get intType {
-    if (_intType == null) {
-      _initializeNumericTypes();
-    }
-    return _intType;
-  }
-
-  @override
-  InterfaceType get iterableDynamicType {
-    if (_iterableDynamicType == null) {
-      _iterableDynamicType = iterableType.instantiate(<DartType>[dynamicType]);
-    }
-    return _iterableDynamicType;
-  }
-
-  @override
-  InterfaceType get iterableObjectType {
-    if (_iterableObjectType == null) {
-      _iterableObjectType = iterableType.instantiate(<DartType>[objectType]);
-    }
-    return _iterableObjectType;
-  }
-
-  @override
-  InterfaceType get iterableType {
-    if (_iterableType == null) {
-      ClassElementImpl iterableElement =
-          ElementFactory.classElement2("Iterable", ["E"]);
-      _iterableType = iterableElement.type;
-      DartType eType = iterableElement.typeParameters[0].type;
-      _setAccessors(iterableElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement(
-            "iterator", false, iteratorType.instantiate(<DartType>[eType])),
-        ElementFactory.getterElement("last", false, eType)
-      ]);
-      iterableElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(iterableElement, '', true)
-          ..isCycleFree = true
-      ];
-      _propagateTypeArguments(iterableElement);
-    }
-    return _iterableType;
-  }
-
-  InterfaceType get iteratorType {
-    if (_iteratorType == null) {
-      ClassElementImpl iteratorElement =
-          ElementFactory.classElement2("Iterator", ["E"]);
-      _iteratorType = iteratorElement.type;
-      DartType eType = iteratorElement.typeParameters[0].type;
-      _setAccessors(iteratorElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement("current", false, eType)
-      ]);
-      iteratorElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(iteratorElement, null, false)
-      ];
-      _propagateTypeArguments(iteratorElement);
-    }
-    return _iteratorType;
-  }
-
-  @override
-  InterfaceType get listType {
-    if (_listType == null) {
-      ClassElementImpl listElement =
-          ElementFactory.classElement2("List", ["E"]);
-      listElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement2(listElement, null)
-      ];
-      _listType = listElement.type;
-      DartType eType = listElement.typeParameters[0].type;
-      InterfaceType iterableType =
-          this.iterableType.instantiate(<DartType>[eType]);
-      listElement.interfaces = <InterfaceType>[iterableType];
-      _setAccessors(listElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement("length", false, intType)
-      ]);
-      listElement.methods = <MethodElement>[
-        ElementFactory.methodElement("[]", eType, [intType]),
-        ElementFactory.methodElement(
-            "[]=", VoidTypeImpl.instance, [intType, eType]),
-        ElementFactory.methodElement("add", VoidTypeImpl.instance, [eType])
-      ];
-      _propagateTypeArguments(listElement);
-    }
-    return _listType;
-  }
-
-  @override
-  InterfaceType get mapObjectObjectType {
-    if (_mapObjectObjectType == null) {
-      _mapObjectObjectType =
-          mapType.instantiate(<DartType>[objectType, objectType]);
-    }
-    return _mapObjectObjectType;
-  }
-
-  @override
-  InterfaceType get mapType {
-    if (_mapType == null) {
-      ClassElementImpl mapElement =
-          ElementFactory.classElement2("Map", ["K", "V"]);
-      _mapType = mapElement.type;
-      DartType kType = mapElement.typeParameters[0].type;
-      DartType vType = mapElement.typeParameters[1].type;
-      _setAccessors(mapElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement("length", false, intType)
-      ]);
-      mapElement.methods = <MethodElement>[
-        ElementFactory.methodElement("[]", vType, [objectType]),
-        ElementFactory.methodElement(
-            "[]=", VoidTypeImpl.instance, [kType, vType])
-      ];
-      mapElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(mapElement, '', false)
-          ..external = true
-          ..factory = true
-      ];
-      _propagateTypeArguments(mapElement);
-    }
-    return _mapType;
-  }
-
-  @override
-  DartType get neverType {
-    return BottomTypeImpl.instance;
-  }
-
-  @override
-  DartObjectImpl get nullObject {
-    if (_nullObject == null) {
-      _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
-    }
-    return _nullObject;
-  }
-
-  @override
-  InterfaceType get nullType {
-    if (_nullType == null) {
-      var nullElement = ElementFactory.classElement2("Null");
-      nullElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(
-            nullElement, '_uninstantiatable', false)
-          ..factory = true
-      ];
-      // Create a library element for "dart:core"
-      // This enables the "isDartCoreNull" getter.
-      var library = new LibraryElementImpl.forNode(
-          _context,
-          null,
-          AstTestFactory.libraryIdentifier2(["dart.core"]),
-          _isNonNullableByDefault);
-      var unit = new CompilationUnitElementImpl();
-      library.definingCompilationUnit = unit;
-      unit.librarySource =
-          unit.source = new StringSource('', null, uri: Uri.parse('dart:core'));
-
-      nullElement.enclosingElement = library;
-      _nullType = nullElement.type;
-    }
-    return _nullType;
-  }
-
-  @override
-  InterfaceType get numType {
-    if (_numType == null) {
-      _initializeNumericTypes();
-    }
-    return _numType;
-  }
-
-  @override
-  InterfaceType get objectType {
-    if (_objectType == null) {
-      ClassElementImpl objectElement = ElementFactory.object;
-      _objectType = objectElement.type;
-      ConstructorElementImpl constructor =
-          ElementFactory.constructorElement(objectElement, '', true);
-      constructor.constantInitializers = <ConstructorInitializer>[];
-      objectElement.constructors = <ConstructorElement>[constructor];
-      objectElement.methods = <MethodElement>[
-        ElementFactory.methodElement("toString", stringType),
-        ElementFactory.methodElement("==", boolType, [_objectType]),
-        ElementFactory.methodElement("noSuchMethod", dynamicType, [dynamicType])
-      ];
-      _setAccessors(objectElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement("hashCode", false, intType),
-        ElementFactory.getterElement("runtimeType", false, typeType)
-      ]);
-    }
-    return _objectType;
-  }
-
-  @override
-  InterfaceType get setType {
-    if (_setType == null) {
-      ClassElementImpl setElement = ElementFactory.classElement2("Set", ["E"]);
-      _setType = setElement.type;
-    }
-    return _setType;
-  }
-
-  @override
-  InterfaceType get stackTraceType {
-    if (_stackTraceType == null) {
-      ClassElementImpl stackTraceElement =
-          ElementFactory.classElement2("StackTrace");
-      stackTraceElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(stackTraceElement, null, false)
-      ];
-      _stackTraceType = stackTraceElement.type;
-    }
-    return _stackTraceType;
-  }
-
-  @override
-  InterfaceType get streamDynamicType {
-    if (_streamDynamicType == null) {
-      _streamDynamicType = streamType.instantiate(<DartType>[dynamicType]);
-    }
-    return _streamDynamicType;
-  }
-
-  @override
-  InterfaceType get streamType {
-    if (_streamType == null) {
-      _streamType = ElementFactory.classElement2("Stream", ["T"]).type;
-    }
-    return _streamType;
-  }
-
-  @override
-  InterfaceType get stringType {
-    if (_stringType == null) {
-      ClassElementImpl stringElement = ElementFactory.classElement2("String");
-      _stringType = stringElement.type;
-      _setAccessors(stringElement, <PropertyAccessorElement>[
-        ElementFactory.getterElement("isEmpty", false, boolType),
-        ElementFactory.getterElement("length", false, intType),
-        ElementFactory.getterElement(
-            "codeUnits", false, listType.instantiate(<DartType>[intType]))
-      ]);
-      stringElement.methods = <MethodElement>[
-        ElementFactory.methodElement("+", _stringType, [_stringType]),
-        ElementFactory.methodElement("toLowerCase", _stringType),
-        ElementFactory.methodElement("toUpperCase", _stringType)
-      ];
-      ConstructorElementImpl fromEnvironment =
-          ElementFactory.constructorElement(
-              stringElement, "fromEnvironment", true);
-      fromEnvironment.parameters = <ParameterElement>[
-        ElementFactory.requiredParameter2("name", stringType),
-        ElementFactory.namedParameter3("defaultValue", type: _stringType)
-      ];
-      fromEnvironment.factory = true;
-      fromEnvironment.isCycleFree = true;
-      stringElement.constructors = <ConstructorElement>[fromEnvironment];
-    }
-    return _stringType;
-  }
-
-  @override
-  InterfaceType get symbolType {
-    if (_symbolType == null) {
-      ClassElementImpl symbolClass = ElementFactory.classElement2("Symbol");
-      ConstructorElementImpl constructor = ElementFactory.constructorElement(
-          symbolClass, '', true, [stringType]);
-      constructor.factory = true;
-      constructor.isCycleFree = true;
-      symbolClass.constructors = <ConstructorElement>[constructor];
-      _symbolType = symbolClass.type;
-    }
-    return _symbolType;
-  }
-
-  @override
-  InterfaceType get typeType {
-    if (_typeType == null) {
-      ClassElementImpl typeClass = ElementFactory.classElement2("Type");
-      typeClass.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(typeClass, null, false)
-          ..isSynthetic = true
-      ];
-      _typeType = typeClass.type;
-    }
-    return _typeType;
-  }
-
-  @override
-  VoidType get voidType => VoidTypeImpl.instance;
-
-  void _initDartAsync() {
-    Source asyncSource;
-    if (_driver != null) {
-      asyncSource = _driver.sourceFactory.forUri(DartSdk.DART_ASYNC);
-    } else if (_context != null) {
-      asyncSource = _context.sourceFactory.forUri(DartSdk.DART_ASYNC);
-      _context.setContents(asyncSource, "");
-    } else {
-      asyncSource = null;
-    }
-    CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
-    LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
-        _context,
-        null,
-        AstTestFactory.libraryIdentifier2(["dart.async"]),
-        _isNonNullableByDefault);
-    asyncLibrary.definingCompilationUnit = asyncUnit;
-    asyncUnit.librarySource = asyncUnit.source = asyncSource;
-
-    ClassElementImpl future = ElementFactory.classElement2("Future", ["T"]);
-    _futureType = future.type;
-    asyncUnit.types = <ClassElement>[future];
-    ClassElementImpl futureOr = ElementFactory.classElement2("FutureOr", ["T"]);
-    _futureOrType = futureOr.type;
-    asyncUnit.types = <ClassElement>[future, futureOr];
-  }
-
-  /**
-   * Initialize the numeric types. They are created as a group so that we can
-   * (a) create the right hierarchy and (b) add members to them.
-   */
-  void _initializeNumericTypes() {
-    //
-    // Create the type hierarchy.
-    //
-    ClassElementImpl numElement = ElementFactory.classElement2("num");
-    _numType = numElement.type;
-    ClassElementImpl intElement = ElementFactory.classElement("int", _numType);
-    _intType = intElement.type;
-    ClassElementImpl doubleElement =
-        ElementFactory.classElement("double", _numType);
-    _doubleType = doubleElement.type;
-    //
-    // Force the referenced types to be cached.
-    //
-    objectType;
-    boolType;
-    nullType;
-    stringType;
-    //
-    // Add the methods.
-    //
-    numElement.methods = <MethodElement>[
-      ElementFactory.methodElement("+", _numType, [_numType]),
-      ElementFactory.methodElement("-", _numType, [_numType]),
-      ElementFactory.methodElement("*", _numType, [_numType]),
-      ElementFactory.methodElement("%", _numType, [_numType]),
-      ElementFactory.methodElement("/", _doubleType, [_numType]),
-      ElementFactory.methodElement("~/", _numType, [_numType]),
-      ElementFactory.methodElement("-", _numType),
-      ElementFactory.methodElement("remainder", _numType, [_numType]),
-      ElementFactory.methodElement("<", _boolType, [_numType]),
-      ElementFactory.methodElement("<=", _boolType, [_numType]),
-      ElementFactory.methodElement(">", _boolType, [_numType]),
-      ElementFactory.methodElement(">=", _boolType, [_numType]),
-      ElementFactory.methodElement("==", _boolType, [_objectType]),
-      ElementFactory.methodElement("abs", _numType),
-      ElementFactory.methodElement("floor", _numType),
-      ElementFactory.methodElement("ceil", _numType),
-      ElementFactory.methodElement("round", _numType),
-      ElementFactory.methodElement("truncate", _numType),
-      ElementFactory.methodElement("toInt", _intType),
-      ElementFactory.methodElement("toDouble", _doubleType),
-      ElementFactory.methodElement("toStringAsFixed", _stringType, [_intType]),
-      ElementFactory.methodElement(
-          "toStringAsExponential", _stringType, [_intType]),
-      ElementFactory.methodElement(
-          "toStringAsPrecision", _stringType, [_intType]),
-      ElementFactory.methodElement("toRadixString", _stringType, [_intType])
-    ];
-    numElement.accessors = [
-      ElementFactory.getterElement('isInfinite', false, _boolType),
-      ElementFactory.getterElement('isNaN', false, _boolType),
-      ElementFactory.getterElement('isNegative', false, _boolType),
-    ];
-    intElement.methods = <MethodElement>[
-      ElementFactory.methodElement("&", _intType, [_intType]),
-      ElementFactory.methodElement("|", _intType, [_intType]),
-      ElementFactory.methodElement("^", _intType, [_intType]),
-      ElementFactory.methodElement("~", _intType),
-      ElementFactory.methodElement("<<", _intType, [_intType]),
-      ElementFactory.methodElement(">>", _intType, [_intType]),
-      ElementFactory.methodElement("-", _intType),
-      ElementFactory.methodElement("abs", _intType),
-      ElementFactory.methodElement("round", _intType),
-      ElementFactory.methodElement("floor", _intType),
-      ElementFactory.methodElement("ceil", _intType),
-      ElementFactory.methodElement("truncate", _intType),
-      ElementFactory.methodElement("toString", _stringType)
-    ];
-    ConstructorElementImpl fromEnvironment =
-        ElementFactory.constructorElement(intElement, "fromEnvironment", true);
-    fromEnvironment.parameters = <ParameterElement>[
-      ElementFactory.requiredParameter2("name", stringType),
-      ElementFactory.namedParameter3("defaultValue", type: _intType)
-    ];
-    fromEnvironment.factory = true;
-    fromEnvironment.isCycleFree = true;
-    numElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement(numElement, null, false)
-        ..isSynthetic = true
-    ];
-    intElement.constructors = <ConstructorElement>[fromEnvironment];
-    doubleElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement(doubleElement, null, false)
-        ..isSynthetic = true
-    ];
-    ConstFieldElementImpl varINFINITY = ElementFactory.fieldElement(
-        "INFINITY", true, false, true, _doubleType,
-        initializer: AstTestFactory.doubleLiteral(double.infinity));
-    varINFINITY.constantInitializer = AstTestFactory.binaryExpression(
-        AstTestFactory.integer(1), TokenType.SLASH, AstTestFactory.integer(0));
-    List<FieldElement> fields = <FieldElement>[
-      ElementFactory.fieldElement("NAN", true, false, true, _doubleType,
-          initializer: AstTestFactory.doubleLiteral(double.nan)),
-      varINFINITY,
-      ElementFactory.fieldElement(
-          "NEGATIVE_INFINITY", true, false, true, _doubleType,
-          initializer: AstTestFactory.doubleLiteral(double.negativeInfinity)),
-      ElementFactory.fieldElement(
-          "MIN_POSITIVE", true, false, true, _doubleType,
-          initializer: AstTestFactory.doubleLiteral(double.minPositive)),
-      ElementFactory.fieldElement("MAX_FINITE", true, false, true, _doubleType,
-          initializer: AstTestFactory.doubleLiteral(double.maxFinite))
-    ];
-    doubleElement.fields = fields;
-    int fieldCount = fields.length;
-    List<PropertyAccessorElement> accessors =
-        new List<PropertyAccessorElement>(fieldCount);
-    for (int i = 0; i < fieldCount; i++) {
-      accessors[i] = fields[i].getter;
-    }
-    doubleElement.accessors = accessors;
-    doubleElement.methods = <MethodElement>[
-      ElementFactory.methodElement("remainder", _doubleType, [_numType]),
-      ElementFactory.methodElement("+", _doubleType, [_numType]),
-      ElementFactory.methodElement("-", _doubleType, [_numType]),
-      ElementFactory.methodElement("*", _doubleType, [_numType]),
-      ElementFactory.methodElement("%", _doubleType, [_numType]),
-      ElementFactory.methodElement("/", _doubleType, [_numType]),
-      ElementFactory.methodElement("~/", _doubleType, [_numType]),
-      ElementFactory.methodElement("-", _doubleType),
-      ElementFactory.methodElement("abs", _doubleType),
-      ElementFactory.methodElement("round", _doubleType),
-      ElementFactory.methodElement("floor", _doubleType),
-      ElementFactory.methodElement("ceil", _doubleType),
-      ElementFactory.methodElement("truncate", _doubleType),
-      ElementFactory.methodElement("toString", _stringType)
-    ];
-  }
-
-  /**
-   * Given a [classElement] representing a class with type parameters, propagate
-   * those type parameters to all of the accessors, methods and constructors
-   * defined for the class.
-   */
-  void _propagateTypeArguments(ClassElementImpl classElement) {
-    for (PropertyAccessorElement accessor in classElement.accessors) {
-      (accessor as ExecutableElementImpl).type = new FunctionTypeImpl(accessor);
-    }
-    for (MethodElement method in classElement.methods) {
-      (method as ExecutableElementImpl).type = new FunctionTypeImpl(method);
-    }
-  }
-
-  /**
-   * Set the accessors for the given class [element] to the given [accessors]
-   * and also set the fields to those that correspond to the accessors.
-   */
-  void _setAccessors(
-      ClassElementImpl element, List<PropertyAccessorElement> accessors) {
-    element.accessors = accessors;
-    element.fields = accessors
-        .map((PropertyAccessorElement accessor) => accessor.variable)
-        .cast<FieldElement>()
-        .toList();
-  }
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 5f02024..2d1444a 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -15,7 +15,9 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/constant/potentially_constant.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/error/lint_codes.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisErrorInfo, AnalysisErrorInfoImpl, AnalysisOptions, Logger;
@@ -280,6 +282,14 @@
     if (element == null || !element.isConst) {
       return false;
     }
+
+    // Ensure that dependencies (e.g. default parameter values) are computed.
+    var implElement = element;
+    if (element is ConstructorMember) {
+      implElement = element.baseElement;
+    }
+    (implElement as ConstructorElementImpl).computeConstantDependencies();
+
     //
     // Verify that the evaluation of the constructor would not produce an
     // exception.
diff --git a/pkg/analyzer/lib/src/plugin/task.dart b/pkg/analyzer/lib/src/plugin/task.dart
deleted file mode 100644
index 54ec75e..0000000
--- a/pkg/analyzer/lib/src/plugin/task.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Support for client code that extends the analysis engine by adding new
- * analysis tasks.
- */
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A function that will create a new [WorkManager] for the given [context].
- */
-typedef WorkManager WorkManagerFactory(InternalAnalysisContext context);
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 70428bf..52439ce 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -590,7 +590,7 @@
         file.path,
         file.uri,
         file.isLibraryDeprecated,
-        file.exportedDeclarations,
+        file.exportedDeclarations ?? const [],
       );
       _idToLibrary[file.id] = library;
       _changesController.add(
@@ -735,7 +735,7 @@
           libraryFile.path,
           libraryFile.uri,
           libraryFile.isLibraryDeprecated,
-          libraryFile.exportedDeclarations,
+          libraryFile.exportedDeclarations ?? const [],
         );
         _idToLibrary[library.id] = library;
         changedLibraries.add(library);
@@ -824,6 +824,9 @@
       case DeclarationKind.FUNCTION_TYPE_ALIAS:
         var name = declaration.name;
         return <String>['$uriStr::$name'];
+      case DeclarationKind.CONSTRUCTOR:
+        var className = declaration.parent.name;
+        return <String>['$uriStr::$className'];
       case DeclarationKind.ENUM_CONSTANT:
         var enumName = declaration.parent.name;
         return <String>['$uriStr::$enumName'];
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index b724baf..b3e3783 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -70,6 +70,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 4601ade..4cfe876 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source_io.dart';
@@ -20,7 +21,6 @@
 import 'package:analyzer/src/summary/expr_builder.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
 
 /**
  * Expando for marking types with implicit type arguments, which are the same as
@@ -413,10 +413,7 @@
   void _buildTypeProvider() {
     _coreLibrary = getLibraryElement('dart:core') as LibraryElementImpl;
     _asyncLibrary = getLibraryElement('dart:async') as LibraryElementImpl;
-    SummaryTypeProvider summaryTypeProvider = new SummaryTypeProvider();
-    summaryTypeProvider.initializeCore(_coreLibrary);
-    summaryTypeProvider.initializeAsync(_asyncLibrary);
-    _typeProvider = summaryTypeProvider;
+    _typeProvider = new TypeProviderImpl(_coreLibrary, _asyncLibrary);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 35966b2..9cf52b7 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -2,14 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart'
     show DartUriResolver, Source, SourceFactory;
@@ -103,278 +98,3 @@
     return _uriResolver.resolveAbsolute(uri);
   }
 }
-
-/**
- * Implementation of [TypeProvider] which can be initialized separately with
- * `dart:core` and `dart:async` libraries.
- */
-class SummaryTypeProvider extends TypeProviderBase {
-  LibraryElement _coreLibrary;
-  LibraryElement _asyncLibrary;
-
-  InterfaceType _boolType;
-  InterfaceType _deprecatedType;
-  InterfaceType _doubleType;
-  InterfaceType _functionType;
-  InterfaceType _futureDynamicType;
-  InterfaceType _futureNullType;
-  InterfaceType _futureOrNullType;
-  InterfaceType _futureOrType;
-  InterfaceType _futureType;
-  InterfaceType _intType;
-  InterfaceType _iterableDynamicType;
-  InterfaceType _iterableObjectType;
-  InterfaceType _iterableType;
-  InterfaceType _listType;
-  InterfaceType _mapType;
-  InterfaceType _mapObjectObjectType;
-  DartObjectImpl _nullObject;
-  InterfaceType _nullType;
-  InterfaceType _numType;
-  InterfaceType _objectType;
-  InterfaceType _setType;
-  InterfaceType _stackTraceType;
-  InterfaceType _streamDynamicType;
-  InterfaceType _streamType;
-  InterfaceType _stringType;
-  InterfaceType _symbolType;
-  InterfaceType _typeType;
-
-  @override
-  InterfaceType get boolType {
-    assert(_coreLibrary != null);
-    _boolType ??= _getType(_coreLibrary, "bool");
-    return _boolType;
-  }
-
-  @override
-  DartType get bottomType => BottomTypeImpl.instanceLegacy;
-
-  @override
-  InterfaceType get deprecatedType {
-    assert(_coreLibrary != null);
-    _deprecatedType ??= _getType(_coreLibrary, "Deprecated");
-    return _deprecatedType;
-  }
-
-  @override
-  InterfaceType get doubleType {
-    assert(_coreLibrary != null);
-    _doubleType ??= _getType(_coreLibrary, "double");
-    return _doubleType;
-  }
-
-  @override
-  DartType get dynamicType => DynamicTypeImpl.instance;
-
-  @override
-  InterfaceType get functionType {
-    assert(_coreLibrary != null);
-    _functionType ??= _getType(_coreLibrary, "Function");
-    return _functionType;
-  }
-
-  @override
-  InterfaceType get futureDynamicType {
-    assert(_asyncLibrary != null);
-    _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
-    return _futureDynamicType;
-  }
-
-  @override
-  InterfaceType get futureNullType {
-    assert(_asyncLibrary != null);
-    _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
-    return _futureNullType;
-  }
-
-  @override
-  InterfaceType get futureOrNullType {
-    assert(_asyncLibrary != null);
-    _futureOrNullType ??= futureOrType.instantiate(<DartType>[nullType]);
-    return _futureOrNullType;
-  }
-
-  @override
-  InterfaceType get futureOrType {
-    assert(_asyncLibrary != null);
-    try {
-      _futureOrType ??= _getType(_asyncLibrary, "FutureOr");
-    } on StateError {
-      // FutureOr<T> is still fairly new, so if we're analyzing an SDK that
-      // doesn't have it yet, create an element for it.
-      _futureOrType =
-          TypeProviderImpl.createPlaceholderFutureOr(futureType, objectType);
-    }
-    return _futureOrType;
-  }
-
-  @override
-  InterfaceType get futureType {
-    assert(_asyncLibrary != null);
-    _futureType ??= _getType(_asyncLibrary, "Future");
-    return _futureType;
-  }
-
-  @override
-  InterfaceType get intType {
-    assert(_coreLibrary != null);
-    _intType ??= _getType(_coreLibrary, "int");
-    return _intType;
-  }
-
-  @override
-  InterfaceType get iterableDynamicType {
-    assert(_coreLibrary != null);
-    _iterableDynamicType ??= iterableType.instantiate(<DartType>[dynamicType]);
-    return _iterableDynamicType;
-  }
-
-  @override
-  InterfaceType get iterableObjectType {
-    assert(_coreLibrary != null);
-    _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
-    return _iterableObjectType;
-  }
-
-  @override
-  InterfaceType get iterableType {
-    assert(_coreLibrary != null);
-    _iterableType ??= _getType(_coreLibrary, "Iterable");
-    return _iterableType;
-  }
-
-  @override
-  InterfaceType get listType {
-    assert(_coreLibrary != null);
-    _listType ??= _getType(_coreLibrary, "List");
-    return _listType;
-  }
-
-  @override
-  InterfaceType get mapObjectObjectType {
-    assert(_coreLibrary != null);
-    return _mapObjectObjectType ??=
-        mapType.instantiate(<DartType>[objectType, objectType]);
-  }
-
-  @override
-  InterfaceType get mapType {
-    assert(_coreLibrary != null);
-    _mapType ??= _getType(_coreLibrary, "Map");
-    return _mapType;
-  }
-
-  @override
-  DartType get neverType => BottomTypeImpl.instance;
-
-  @override
-  DartObjectImpl get nullObject {
-    if (_nullObject == null) {
-      _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
-    }
-    return _nullObject;
-  }
-
-  @override
-  InterfaceType get nullType {
-    assert(_coreLibrary != null);
-    _nullType ??= _getType(_coreLibrary, "Null");
-    return _nullType;
-  }
-
-  @override
-  InterfaceType get numType {
-    assert(_coreLibrary != null);
-    _numType ??= _getType(_coreLibrary, "num");
-    return _numType;
-  }
-
-  @override
-  InterfaceType get objectType {
-    assert(_coreLibrary != null);
-    _objectType ??= _getType(_coreLibrary, "Object");
-    return _objectType;
-  }
-
-  @override
-  InterfaceType get setType {
-    assert(_coreLibrary != null);
-    return _setType ??= _getType(_coreLibrary, "Set");
-  }
-
-  @override
-  InterfaceType get stackTraceType {
-    assert(_coreLibrary != null);
-    _stackTraceType ??= _getType(_coreLibrary, "StackTrace");
-    return _stackTraceType;
-  }
-
-  @override
-  InterfaceType get streamDynamicType {
-    assert(_asyncLibrary != null);
-    _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
-    return _streamDynamicType;
-  }
-
-  @override
-  InterfaceType get streamType {
-    assert(_asyncLibrary != null);
-    _streamType ??= _getType(_asyncLibrary, "Stream");
-    return _streamType;
-  }
-
-  @override
-  InterfaceType get stringType {
-    assert(_coreLibrary != null);
-    _stringType ??= _getType(_coreLibrary, "String");
-    return _stringType;
-  }
-
-  @override
-  InterfaceType get symbolType {
-    assert(_coreLibrary != null);
-    _symbolType ??= _getType(_coreLibrary, "Symbol");
-    return _symbolType;
-  }
-
-  @override
-  InterfaceType get typeType {
-    assert(_coreLibrary != null);
-    _typeType ??= _getType(_coreLibrary, "Type");
-    return _typeType;
-  }
-
-  @override
-  VoidType get voidType => VoidTypeImpl.instance;
-
-  /**
-   * Initialize the `dart:async` types provided by this type provider.
-   */
-  void initializeAsync(LibraryElement library) {
-    assert(_coreLibrary != null);
-    assert(_asyncLibrary == null);
-    _asyncLibrary = library;
-  }
-
-  /**
-   * Initialize the `dart:core` types provided by this type provider.
-   */
-  void initializeCore(LibraryElement library) {
-    assert(_coreLibrary == null);
-    assert(_asyncLibrary == null);
-    _coreLibrary = library;
-  }
-
-  /**
-   * Return the type with the given [name] from the given [library], or
-   * throw a [StateError] if there is no class with the given name.
-   */
-  InterfaceType _getType(LibraryElement library, String name) {
-    Element element = library.getType(name);
-    if (element == null) {
-      throw new StateError("No definition of type $name");
-    }
-    return (element as ClassElement).type;
-  }
-}
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 23235b0..fef52b3 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -652,8 +652,8 @@
       ),
       metadata: _readNodeList(data.normalFormalParameter_metadata),
       comment: _readDocumentationComment(data),
-      type: _readNode(data.fieldFormalParameter_type),
-      parameters: _readNode(data.fieldFormalParameter_formalParameters),
+      type: _readNodeLazy(data.fieldFormalParameter_type),
+      parameters: _readNodeLazy(data.fieldFormalParameter_formalParameters),
       requiredKeyword:
           AstBinaryFlags.isRequired(data.flags) ? _Tokens.REQUIRED : null,
     );
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 54f48bf..7ee9b12 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -45,8 +45,19 @@
   @override
   LinkedNodeBuilder visitAnnotation(Annotation node) {
     var elementComponents = _componentsOfElement(node.element);
+
+    LinkedNodeBuilder storedArguments;
+    var arguments = node.arguments;
+    if (arguments != null) {
+      if (arguments.arguments.every(_isSerializableExpression)) {
+        storedArguments = arguments.accept(this);
+      } else {
+        storedArguments = LinkedNodeBuilder.argumentList();
+      }
+    }
+
     return LinkedNodeBuilder.annotation(
-      annotation_arguments: node.arguments?.accept(this),
+      annotation_arguments: storedArguments,
       annotation_constructorName: node.constructorName?.accept(this),
       annotation_element: elementComponents.rawElement,
       annotation_substitution: elementComponents.substitution,
@@ -1356,6 +1367,10 @@
       }
     }
 
+    if (!_isSerializableExpression(initializer)) {
+      initializer = null;
+    }
+
     var builder = LinkedNodeBuilder.variableDeclaration(
       informativeId: getInformativeId(node),
       variableDeclaration_initializer: initializer?.accept(this),
diff --git a/pkg/analyzer/lib/src/summary2/export.dart b/pkg/analyzer/lib/src/summary2/export.dart
index 18247c3..a84d39e 100644
--- a/pkg/analyzer/lib/src/summary2/export.dart
+++ b/pkg/analyzer/lib/src/summary2/export.dart
@@ -2,13 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
 import 'package:analyzer/src/summary2/combinator.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 
 class Export {
-  final SourceLibraryBuilder exporter;
-  final SourceLibraryBuilder exported;
+  final LibraryBuilder exporter;
+  final LibraryBuilder exported;
   final List<Combinator> combinators;
 
   Export(this.exporter, this.exported, this.combinators);
diff --git a/pkg/analyzer/lib/src/summary2/function_type_builder.dart b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
index 836b1cf..3153f3b 100644
--- a/pkg/analyzer/lib/src/summary2/function_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
@@ -63,18 +63,19 @@
       return _type;
     }
 
+    for (TypeParameterElementImpl typeParameter in typeFormals) {
+      typeParameter.bound = _buildType(typeParameter.bound);
+    }
+
+    for (ParameterElementImpl parameter in parameters) {
+      parameter.type = _buildType(parameter.type);
+    }
+
     var builtReturnType = _buildType(returnType);
     _type = FunctionTypeImpl.synthetic(
       builtReturnType,
       typeFormals,
-      parameters.map((e) {
-        return ParameterElementImpl.synthetic(
-          e.name,
-          _buildType(e.type),
-          // ignore: deprecated_member_use_from_same_package
-          e.parameterKind,
-        );
-      }).toList(),
+      parameters,
       nullabilitySuffix: nullabilitySuffix,
     );
 
diff --git a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
similarity index 98%
rename from pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
rename to pkg/analyzer/lib/src/summary2/library_builder.dart
index aad7c03..f02bc83 100644
--- a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -24,7 +24,7 @@
 import 'package:analyzer/src/summary2/scope.dart';
 import 'package:analyzer/src/summary2/types_builder.dart';
 
-class SourceLibraryBuilder {
+class LibraryBuilder {
   final Linker linker;
   final Uri uri;
   final Reference reference;
@@ -43,7 +43,7 @@
 
   final List<Export> exporters = [];
 
-  SourceLibraryBuilder(this.linker, this.uri, this.reference, this.node);
+  LibraryBuilder(this.linker, this.uri, this.reference, this.node);
 
   void addExporters() {
     var unitContext = context.units[0];
@@ -335,7 +335,7 @@
       }
     }
 
-    var builder = SourceLibraryBuilder(
+    var builder = LibraryBuilder(
       linker,
       libraryUri,
       libraryReference,
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 9f09487..8e91cf7 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -6,15 +6,15 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:analyzer/src/summary2/ast_binary_writer.dart';
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
 import 'package:analyzer/src/summary2/linked_bundle_context.dart';
 import 'package:analyzer/src/summary2/linked_element_factory.dart';
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
@@ -44,7 +44,7 @@
   LinkingBundleContext linkingBundleContext;
 
   /// Libraries that are being linked.
-  final Map<Uri, SourceLibraryBuilder> builders = {};
+  final Map<Uri, LibraryBuilder> builders = {};
 
   InheritanceManager3 inheritance; // TODO(scheglov) cache it
 
@@ -75,7 +75,7 @@
 
   void link(List<LinkInputLibrary> inputLibraries) {
     for (var inputLibrary in inputLibraries) {
-      SourceLibraryBuilder.build(this, inputLibrary);
+      LibraryBuilder.build(this, inputLibrary);
     }
     // TODO(scheglov) do in build() ?
     elementFactory.addBundle(bundleContext);
@@ -122,8 +122,8 @@
       library.buildInitialExportScope();
     }
 
-    var exporters = new Set<SourceLibraryBuilder>();
-    var exportees = new Set<SourceLibraryBuilder>();
+    var exporters = new Set<LibraryBuilder>();
+    var exportees = new Set<LibraryBuilder>();
 
     for (var library in builders.values) {
       library.addExporters();
@@ -138,7 +138,7 @@
       }
     }
 
-    var both = new Set<SourceLibraryBuilder>();
+    var both = new Set<LibraryBuilder>();
     for (var exported in exportees) {
       if (exporters.contains(exported)) {
         both.add(exported);
@@ -212,10 +212,7 @@
 
     var coreLib = elementFactory.libraryOfUri('dart:core');
     var asyncLib = elementFactory.libraryOfUri('dart:async');
-
-    analysisContext.typeProvider = SummaryTypeProvider()
-      ..initializeCore(coreLib)
-      ..initializeAsync(asyncLib);
+    analysisContext.typeProvider = TypeProviderImpl(coreLib, asyncLib);
 
     inheritance = InheritanceManager3(typeSystem);
   }
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 2b30438..801f3b0 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -647,7 +647,7 @@
     } else if (node is ExtensionDeclaration) {
       return node.typeParameters;
     } else if (node is FieldFormalParameter) {
-      return null;
+      return node.typeParameters;
     } else if (node is FunctionDeclaration) {
       LazyFunctionDeclaration.readFunctionExpression(_astReader, node);
       return getTypeParameters2(node.functionExpression);
diff --git a/pkg/analyzer/lib/src/summary2/named_type_builder.dart b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
index c90c6a8..ff94d7d 100644
--- a/pkg/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
@@ -185,15 +185,6 @@
     }
   }
 
-  /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
-  DartType _buildType(DartType type) {
-    if (type is TypeBuilder) {
-      return type.build();
-    } else {
-      return type;
-    }
-  }
-
   DartType _getRawFunctionType(GenericTypeAliasElementImpl element) {
     // If the element is not being linked, there is no reason (or a way,
     // because the linked node might be read only partially) to go through
@@ -218,22 +209,31 @@
       );
     } else if (typedefNode is GenericTypeAlias) {
       var functionNode = typedefNode.functionType;
-      if (functionNode != null) {
-        return _buildFunctionType(
-          element,
-          _typeParameterTypes(typedefNode.typeParameters),
-          functionNode.typeParameters,
-          functionNode.returnType,
-          functionNode.parameters,
+      var functionType = _buildType(functionNode?.type);
+      if (functionType is FunctionType) {
+        return FunctionTypeImpl.synthetic(
+          functionType.returnType,
+          functionType.typeFormals,
+          functionType.parameters,
+          element: element,
+          typeArguments: _typeParameterTypes(typedefNode.typeParameters),
         );
-      } else {
-        return _dynamicType;
       }
+      return _dynamicType;
     } else {
       throw StateError('(${element.runtimeType}) $element');
     }
   }
 
+  /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
+  static DartType _buildType(DartType type) {
+    if (type is TypeBuilder) {
+      return type.build();
+    } else {
+      return type;
+    }
+  }
+
   static List<DartType> _listOfDynamic(int length) {
     return List<DartType>.filled(length, _dynamicType);
   }
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 3d780ac..3187ffa 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -206,9 +206,33 @@
 
   @override
   void visitFieldFormalParameter(FieldFormalParameter node) {
+    var outerScope = scope;
+    var outerReference = reference;
+
+    var name = node.identifier.name;
+    reference = reference.getChild('@parameter').getChild(name);
+    reference.node = node;
+
+    var element = ParameterElementImpl.forLinkedNode(
+      outerReference.element,
+      reference,
+      node,
+    );
+    node.identifier.staticElement = element;
+    _createTypeParameterElements(node.typeParameters);
+
+    scope = new EnclosedScope(scope);
+    for (var typeParameter in element.typeParameters) {
+      scope.define(typeParameter);
+    }
+
     node.type?.accept(this);
+    node.typeParameters?.accept(this);
     node.parameters?.accept(this);
     nodesToBuildType.addDeclaration(node);
+
+    scope = outerScope;
+    reference = outerReference;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index e1bbe8a..3ae599f 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -7,8 +7,8 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary/link.dart' as graph
     show DependencyWalker, Node;
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
 import 'package:analyzer/src/summary2/linked_bundle_context.dart';
 
 /// Compute simple-boundedness for all classes and generic types aliases in
@@ -16,7 +16,7 @@
 /// so they all should be processed simultaneously.
 void computeSimplyBounded(
   LinkedBundleContext bundleContext,
-  Iterable<SourceLibraryBuilder> libraryBuilders,
+  Iterable<LibraryBuilder> libraryBuilders,
 ) {
   var walker = SimplyBoundedDependencyWalker(bundleContext);
   var nodes = <SimplyBoundedNode>[];
@@ -302,6 +302,8 @@
   void visitParameter(FormalParameter node) {
     if (node is DefaultFormalParameter) {
       visitParameter(node.parameter);
+    } else if (node is FieldFormalParameter) {
+      // The spec does not allow them here, ignore.
     } else if (node is FunctionTypedFormalParameter) {
       addType(node.returnType);
       visitParameters(node.parameters);
diff --git a/pkg/analyzer/lib/src/task/api/dart.dart b/pkg/analyzer/lib/src/task/api/dart.dart
deleted file mode 100644
index 9064e25..0000000
--- a/pkg/analyzer/lib/src/task/api/dart.dart
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * The analysis errors associated with a [Source] representing a compilation
- * unit.
- */
-final ListResultDescriptor<AnalysisError> DART_ERRORS =
-    new ListResultDescriptor<AnalysisError>(
-        'DART_ERRORS', AnalysisError.NO_ERRORS);
-
-/**
- * The sources of the libraries that are explicitly imported into a library.
- *
- * The list will be empty if there are no explicit imports, but will not be
- * `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> EXPLICITLY_IMPORTED_LIBRARIES =
-    new ListResultDescriptor<Source>(
-        'EXPLICITLY_IMPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the libraries that are exported from a library.
- *
- * The list will be empty if there are no exported libraries, but will not be
- * `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> EXPORTED_LIBRARIES =
-    new ListResultDescriptor<Source>('EXPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the libraries that are implicitly or explicitly imported into
- * a library.
- *
- * The list will minimally contain the source for `dart:core` because it is
- * implicitly imported into every library, and therefore will never be `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> IMPORTED_LIBRARIES =
-    new ListResultDescriptor<Source>('IMPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the parts that are included in a library.
- *
- * The list will be empty if there are no parts, but will not be `null`. The
- * list does *not* include the source for the defining compilation unit.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> INCLUDED_PARTS =
-    new ListResultDescriptor<Source>('INCLUDED_PARTS', const <Source>[]);
-
-/**
- * A flag specifying whether a library is launchable.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<bool> IS_LAUNCHABLE =
-    new ResultDescriptor<bool>('IS_LAUNCHABLE', false);
-
-/**
- * The fully built [LibraryElement] associated with a library.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT =
-    new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT', null);
-
-/**
- * The compilation unit AST produced while parsing a compilation unit.
- *
- * The AST structure will not have resolution information associated with it.
- *
- * The result is only available for [Source]s representing a compilation unit.
- */
-final ResultDescriptor<CompilationUnit> PARSED_UNIT =
-    new ResultDescriptor<CompilationUnit>('PARSED_UNIT', null);
-
-/**
- * The resolved [CompilationUnit] associated with a compilation unit, with
- * constants resolved.
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ResultDescriptor<CompilationUnit> RESOLVED_UNIT =
-    new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT', null);
-
-/**
- * The kind of a [Source].
- */
-final ResultDescriptor<SourceKind> SOURCE_KIND =
-    new ResultDescriptor<SourceKind>('SOURCE_KIND', SourceKind.UNKNOWN);
-
-/**
- * The token stream produced while scanning a compilation unit.
- *
- * The value is the first token in the file, or the special end-of-file marker
- * at the end of the stream if the file does not contain any tokens.
- *
- * The result is only available for [Source]s representing a compilation unit.
- */
-final ResultDescriptor<Token> TOKEN_STREAM =
-    new ResultDescriptor<Token>('TOKEN_STREAM', null);
-
-/**
- * The sources of the Dart files that a library consists of.
- *
- * The list will include the source of the defining unit and [INCLUDED_PARTS].
- * So, it is never empty or `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> UNITS =
-    new ListResultDescriptor<Source>('UNITS', const <Source>[]);
-
-/**
- * A specific compilation unit in a specific library.
- *
- * This kind of target is associated with information about a compilation unit
- * that differs based on the library that the unit is a part of. For example,
- * the result of resolving a compilation unit depends on the imports, which can
- * change if a single part is included in more than one library.
- */
-class LibrarySpecificUnit implements AnalysisTarget {
-  /**
-   * The defining compilation unit of the library in which the [unit]
-   * is analyzed.
-   */
-  final Source library;
-
-  /**
-   * The compilation unit which belongs to the [library].
-   */
-  final Source unit;
-
-  /**
-   * Initialize a newly created target for the [unit] in the [library].
-   */
-  LibrarySpecificUnit(this.library, this.unit);
-
-  @override
-  int get hashCode {
-    return JenkinsSmiHash.combine(library.hashCode, unit.hashCode);
-  }
-
-  @override
-  Source get librarySource => library;
-
-  @override
-  Source get source => unit;
-
-  @override
-  bool operator ==(other) {
-    return other is LibrarySpecificUnit &&
-        other.library == library &&
-        other.unit == unit;
-  }
-
-  @override
-  String toString() => '$unit in $library';
-}
diff --git a/pkg/analyzer/lib/src/task/api/general.dart b/pkg/analyzer/lib/src/task/api/general.dart
deleted file mode 100644
index d884116..0000000
--- a/pkg/analyzer/lib/src/task/api/general.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * The content of a [Source].
- */
-final ResultDescriptor<String> CONTENT =
-    new ResultDescriptor<String>('CONTENT', null);
-
-/**
- * The line information for a [Source].
- */
-final ResultDescriptor<LineInfo> LINE_INFO =
-    new ResultDescriptor<LineInfo>('LINE_INFO', null);
-
-/**
- * The modification time of a [Source].
- */
-final ResultDescriptor<int> MODIFICATION_TIME =
-    new ResultDescriptor<int>('MODIFICATION_TIME', -1);
diff --git a/pkg/analyzer/lib/src/task/api/model.dart b/pkg/analyzer/lib/src/task/api/model.dart
index 05c8b23..da0d3db 100644
--- a/pkg/analyzer/lib/src/task/api/model.dart
+++ b/pkg/analyzer/lib/src/task/api/model.dart
@@ -2,68 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:collection';
-import 'dart:developer';
-
-import 'package:analyzer/error/error.dart' show AnalysisError;
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/driver.dart';
-import 'package:analyzer/src/task/model.dart';
-
-/**
- * A function that converts the given [key] and [value] into a [TaskInput].
- */
-typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value);
-
-/**
- * A function that takes an analysis [context] and an analysis [target] and
- * returns an analysis task. Such functions are passed to a [TaskDescriptor] to
- * be used to create the described task.
- */
-typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target);
-
-/**
- * A function that takes the target for which a task will produce results and
- * returns a map from input names to descriptions of the analysis results needed
- * by the task in order for the task to be performed. Such functions are passed
- * to a [TaskDescriptor] to be used to determine the inputs needed by the task.
- */
-typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
-
-/**
- * A function that takes the target for which a task will produce results and
- * returns an indication of how suitable the task is for the target. Such
- * functions are passed to a [TaskDescriptor] to be used to determine their
- * suitability for computing results.
- */
-typedef TaskSuitability SuitabilityFor(AnalysisTarget target);
-
-/**
- * A function that converts an object of the type [B] into a [TaskInput].
- * This is used, for example, by a [ListTaskInput] to create task inputs
- * for each value in a list of values.
- */
-typedef TaskInput<E> UnaryFunction<B, E>(B object);
-
-/**
- * An [AnalysisTarget] wrapper for an [AnalysisContext].
- */
-class AnalysisContextTarget implements AnalysisTarget {
-  static final AnalysisContextTarget request = new AnalysisContextTarget(null);
-
-  final AnalysisContext context;
-
-  AnalysisContextTarget(this.context);
-
-  @override
-  Source get librarySource => null;
-
-  @override
-  Source get source => null;
-}
 
 /**
  * An object with which an analysis result can be associated.
@@ -85,713 +24,3 @@
    */
   Source get source;
 }
-
-/**
- * An object used to compute one or more analysis results associated with a
- * single target.
- *
- * Clients must extend this class when creating new tasks.
- */
-abstract class AnalysisTask {
-  /**
-   * A queue storing the last 10 task descriptions for diagnostic purposes.
-   */
-  static final LimitedQueue<String> LAST_TASKS = new LimitedQueue<String>(10);
-
-  /**
-   * A table mapping the types of analysis tasks to the number of times each
-   * kind of task has been performed.
-   */
-  static final Map<Type, int> countMap = new HashMap<Type, int>();
-
-  /**
-   * A table mapping the types of analysis tasks to user tags used to collect
-   * timing data for the Observatory.
-   */
-  static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>();
-
-  /**
-   * A table mapping the types of analysis tasks to stopwatches used to compute
-   * how much time was spent executing each kind of task.
-   */
-  static final Map<Type, Stopwatch> stopwatchMap =
-      new HashMap<Type, Stopwatch>();
-
-  /**
-   * The context in which the task is to be performed.
-   */
-  final AnalysisContext context;
-
-  /**
-   * The target for which result values are being produced.
-   */
-  final AnalysisTarget target;
-
-  /**
-   * A table mapping input names to input values.
-   */
-  Map<String, dynamic> inputs;
-
-  /**
-   * A table mapping result descriptors whose values are produced by this task
-   * to the values that were produced.
-   */
-  Map<ResultDescriptor, dynamic> outputs =
-      new HashMap<ResultDescriptor, dynamic>();
-
-  /**
-   * The exception that was thrown while performing this task, or `null` if the
-   * task completed successfully.
-   */
-  CaughtException caughtException;
-
-  /**
-   * If a dependency cycle was found while computing the inputs for the task,
-   * the set of [WorkItem]s contained in the cycle (if there are overlapping
-   * cycles, this is the set of all [WorkItem]s in the entire strongly
-   * connected component).  Otherwise, `null`.
-   */
-  List<WorkItem> dependencyCycle;
-
-  /**
-   * Initialize a newly created task to perform analysis within the given
-   * [context] in order to produce results for the given [target].
-   */
-  AnalysisTask(this.context, this.target);
-
-  /**
-   * Return a textual description of this task.
-   */
-  String get description;
-
-  /**
-   * Return the descriptor that describes this task.
-   */
-  TaskDescriptor get descriptor;
-
-  /**
-   * Indicates whether the task is capable of handling dependency cycles.  A
-   * task that overrides this getter to return `true` must be prepared for the
-   * possibility that it will be invoked with a non-`null` value of
-   * [dependencyCycle], and with not all of its inputs computed.
-   */
-  bool get handlesDependencyCycles => false;
-
-  /**
-   * Return the value of the input with the given [name], or `null` if the input
-   * value is not defined.
-   */
-  Object getOptionalInput(String name) {
-    if (inputs == null || !inputs.containsKey(name)) {
-      return null;
-    }
-    return inputs[name];
-  }
-
-  /**
-   * Return the value of the input with the given [name]. Throw an exception if
-   * the input value is not defined.
-   */
-  E getRequiredInput<E>(String name) {
-    if (inputs == null || !inputs.containsKey(name)) {
-      throw new AnalysisException("Could not $description: missing $name");
-    }
-    if (inputs[name] is! E) {
-      throw new AnalysisException(
-          "Could not $description: $name is a ${inputs[name].runtimeType} rather than a $E");
-    }
-    return inputs[name] as E;
-  }
-
-  /**
-   * Return the source associated with the target. Throw an exception if
-   * the target is not associated with a source.
-   */
-  Source getRequiredSource() {
-    Source source = target.source;
-    if (source == null) {
-      throw new AnalysisException("Could not $description: missing source");
-    }
-    return source;
-  }
-
-  /**
-   * Perform this analysis task, protected by an exception handler.
-   *
-   * This method should throw an [AnalysisException] if an exception occurs
-   * while performing the task. If other kinds of exceptions are thrown they
-   * will be wrapped in an [AnalysisException].
-   *
-   * If no exception is thrown, this method must fully populate the [outputs]
-   * map (have a key/value pair for each result that this task is expected to
-   * produce).
-   */
-  void internalPerform();
-
-  /**
-   * Perform this analysis task. When this method returns, either the [outputs]
-   * map should be fully populated (have a key/value pair for each result that
-   * this task is expected to produce) or the [caughtException] should be set.
-   *
-   * Clients may not override this method.
-   */
-  void perform() {
-    try {
-      _safelyPerform();
-    } on AnalysisException catch (exception, stackTrace) {
-      caughtException = new CaughtException(exception, stackTrace);
-      AnalysisEngine.instance.logger
-          .logError("Task failed: $description", caughtException);
-    }
-  }
-
-  @override
-  String toString() => description;
-
-  /**
-   * Given a strongly connected component, find and return a list of
-   * [TargetedResult]s that describes a cyclic path within the cycle.  Returns
-   * null if no cyclic path is found.
-   */
-  List<TargetedResult> _findCyclicPath(List<WorkItem> cycle) {
-    WorkItem findInCycle(AnalysisTarget target, ResultDescriptor descriptor) {
-      for (WorkItem item in cycle) {
-        if (target == item.target && descriptor == item.spawningResult) {
-          return item;
-        }
-      }
-      return null;
-    }
-
-    HashSet<WorkItem> active = new HashSet<WorkItem>();
-    List<TargetedResult> path = null;
-    bool traverse(WorkItem item) {
-      if (!active.add(item)) {
-        // We've found a cycle
-        path = <TargetedResult>[];
-        return true;
-      }
-      for (TargetedResult result in item.inputTargetedResults) {
-        WorkItem item = findInCycle(result.target, result.result);
-        // Ignore edges that leave the cycle.
-        if (item != null) {
-          if (traverse(item)) {
-            // This edge is in a cycle (or leads to a cycle) so add it to the
-            // path
-            path.add(result);
-            return true;
-          }
-        }
-      }
-      // There was no cycle.
-      return false;
-    }
-
-    if (cycle.isNotEmpty) {
-      traverse(cycle[0]);
-    }
-    return path;
-  }
-
-  /**
-   * Perform this analysis task, ensuring that all exceptions are wrapped in an
-   * [AnalysisException].
-   *
-   * Clients may not override this method.
-   */
-  void _safelyPerform() {
-    try {
-      //
-      // Store task description for diagnostics.
-      //
-      LAST_TASKS.add(description);
-
-      //
-      // Report that this task is being performed.
-      //
-      String contextName = context.name;
-      if (contextName == null) {
-        contextName = 'unnamed';
-      }
-      AnalysisEngine.instance.instrumentationService
-          .logAnalysisTask(contextName, this);
-      //
-      // Gather statistics on the performance of the task.
-      //
-      int count = countMap[runtimeType];
-      countMap[runtimeType] = count == null ? 1 : count + 1;
-//      UserTag tag = tagMap.putIfAbsent(
-//          runtimeType, () => new UserTag(runtimeType.toString()));
-      Stopwatch stopwatch = stopwatchMap[runtimeType];
-      if (stopwatch == null) {
-        stopwatch = new Stopwatch();
-        stopwatchMap[runtimeType] = stopwatch;
-      }
-//      UserTag previousTag = tag.makeCurrent();
-//      try {
-      stopwatch.start();
-      //
-      // Actually perform the task.
-      //
-      try {
-        if (dependencyCycle != null && !handlesDependencyCycles) {
-          throw new InfiniteTaskLoopException(
-              this, dependencyCycle, _findCyclicPath(dependencyCycle));
-        }
-        internalPerform();
-      } finally {
-        stopwatch.stop();
-      }
-//      } finally {
-//        previousTag.makeCurrent();
-//      }
-    } on AnalysisException {
-      rethrow;
-    } on ModificationTimeMismatchError {
-      rethrow;
-    } catch (exception, stackTrace) {
-      throw new AnalysisException(
-          'Unexpected exception while performing $description',
-          new CaughtException(exception, stackTrace));
-    }
-  }
-}
-
-/**
- * A description of a [List]-based analysis result that can be computed by an
- * [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
-  /**
-   * Initialize a newly created analysis result to have the given [name] and
-   * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
-   * values associated with this result will remain in the cache.
-   */
-  factory ListResultDescriptor(String name, List<E> defaultValue,
-      {ResultCachingPolicy cachingPolicy}) = ListResultDescriptorImpl<E>;
-
-  @override
-  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
-}
-
-/**
- * A description of an input to an [AnalysisTask] that can be used to compute
- * that input.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ListTaskInput<E> implements TaskInput<List<E>> {
-  /**
-   * Return a task input that can be used to compute a flatten list whose
-   * elements are combined [subListResult]'s associated with those elements.
-   */
-  ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult);
-
-  /**
-   * Return a task input that can be used to compute a list whose elements are
-   * the result of passing the elements of this input to the [mapper] function.
-   */
-  ListTaskInput<V> toList<V>(UnaryFunction<E, V> mapper);
-
-  /**
-   * Return a task input that can be used to compute a list whose elements are
-   * [valueResult]'s associated with those elements.
-   */
-  ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult);
-
-  /**
-   * Return a task input that can be used to compute a map whose keys are the
-   * elements of this input and whose values are the result of passing the
-   * corresponding key to the [mapper] function.
-   */
-  MapTaskInput<E, V> toMap<V>(UnaryFunction<E, V> mapper);
-
-  /**
-   * Return a task input that can be used to compute a map whose keys are the
-   * elements of this input and whose values are the [valueResult]'s associated
-   * with those elements.
-   */
-  MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult);
-}
-
-/**
- * A description of an input with a [Map] based values.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class MapTaskInput<K, V> implements TaskInput<Map<K, V>> {
-  /**
-   * [V] must be a [List].
-   * Return a task input that can be used to compute a list whose elements are
-   * the result of passing keys [K] and the corresponding elements of [V] to
-   * the [mapper] function.
-   */
-  TaskInput<List<E>> toFlattenList<E>(
-      BinaryFunction<K, dynamic /*element of V*/, E> mapper);
-}
-
-/**
- * Instances of this class are thrown when a task detects that the modification
- * time of a cache entry is not the same as the actual modification time.  This
- * means that any analysis results based on the content of the target cannot be
- * used anymore and must be invalidated.
- */
-class ModificationTimeMismatchError {
-  final Source source;
-
-  ModificationTimeMismatchError(this.source);
-}
-
-/**
- * A policy object that can compute sizes of results and provide the maximum
- * active and idle sizes that can be kept in the cache.
- *
- * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
- * share the same total size in a cache.
- *
- * Clients may implement this class when implementing plugins.
- */
-abstract class ResultCachingPolicy {
-  /**
-   * Return the maximum total size of results that can be kept in the cache
-   * while analysis is in progress.
-   */
-  int get maxActiveSize;
-
-  /**
-   * Return the maximum total size of results that can be kept in the cache
-   * while analysis is idle.
-   */
-  int get maxIdleSize;
-
-  /**
-   * Return the size of the given [object].
-   */
-  int measure(Object object);
-}
-
-/**
- * A description of an analysis result that can be computed by an [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ResultDescriptor<V> {
-  /**
-   * A comparator that can be used to sort result descriptors by their name.
-   */
-  static final Comparator<ResultDescriptor> SORT_BY_NAME =
-      (ResultDescriptor first, ResultDescriptor second) =>
-          first.name.compareTo(second.name);
-
-  /**
-   * Initialize a newly created analysis result to have the given [name] and
-   * [defaultValue].
-   *
-   * The given [cachingPolicy] is used to limit the total size of results
-   * described by this descriptor. If no policy is specified, the results are
-   * never evicted from the cache, and removed only when they are invalidated.
-   */
-  factory ResultDescriptor(String name, V defaultValue,
-      {ResultCachingPolicy cachingPolicy}) = ResultDescriptorImpl<V>;
-
-  /**
-   * Return the caching policy for results described by this descriptor.
-   */
-  ResultCachingPolicy get cachingPolicy;
-
-  /**
-   * Return the default value for results described by this descriptor.
-   */
-  V get defaultValue;
-
-  /**
-   * Return the name of this descriptor.
-   */
-  String get name;
-
-  /**
-   * Return a task input that can be used to compute this result for the given
-   * [target]. If [flushOnAccess] is `true` then the value of this result that
-   * is associated with the [target] will be flushed when it is accessed.
-   */
-  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
-}
-
-/**
- * A specification of the given [result] for the given [target].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-class TargetedResult {
-  /**
-   * The target with which the result is associated.
-   */
-  final AnalysisTarget target;
-
-  /**
-   * The result associated with the target.
-   */
-  final ResultDescriptor result;
-
-  /**
-   * Initialize a new targeted result.
-   */
-  TargetedResult(this.target, this.result);
-
-  @override
-  int get hashCode {
-    return JenkinsSmiHash.combine(target.hashCode, result.hashCode);
-  }
-
-  @override
-  bool operator ==(other) {
-    return other is TargetedResult &&
-        other.target == target &&
-        other.result == result;
-  }
-
-  @override
-  String toString() => '$result for $target';
-}
-
-/**
- * A description of an [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskDescriptor {
-  /**
-   * Initialize a newly created task descriptor to have the given [name] and to
-   * describe a task that takes the inputs built using the given [inputBuilder],
-   * and produces the given [results]. The [buildTask] function will be used to
-   * create the instance of [AnalysisTask] being described. If provided, the
-   * [isAppropriateFor] function will be used to determine whether the task can
-   * be used on a specific target.
-   */
-  factory TaskDescriptor(String name, BuildTask buildTask,
-      CreateTaskInputs inputBuilder, List<ResultDescriptor> results,
-      {SuitabilityFor suitabilityFor}) = TaskDescriptorImpl;
-
-  /**
-   * Return the builder used to build the inputs to the task.
-   */
-  CreateTaskInputs get createTaskInputs;
-
-  /**
-   * Return the name of the task being described.
-   */
-  String get name;
-
-  /**
-   * Return a list of the analysis results that will be computed by this task.
-   */
-  List<ResultDescriptor> get results;
-
-  /**
-   * Create and return a task that is described by this descriptor that can be
-   * used to compute results based on the given [inputs].
-   */
-  AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
-      Map<String, dynamic> inputs);
-
-  /**
-   * Return an indication of how suitable this task is for the given [target].
-   */
-  TaskSuitability suitabilityFor(AnalysisTarget target);
-}
-
-/**
- * A description of an input to an [AnalysisTask] that can be used to compute
- * that input.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskInput<V> {
-  /**
-   * Create and return a builder that can be used to build this task input.
-   */
-  TaskInputBuilder<V> createBuilder();
-
-  /**
-   * Return a task input that can be used to compute a list whose elements are
-   * the result of passing the result of this input to the [mapper] function.
-   */
-  ListTaskInput<E> mappedToList<E>(List<E> mapper(V value));
-}
-
-/**
- * An object used to build the value associated with a single [TaskInput].
- *
- * All builders work by requesting one or more results (each result being
- * associated with a target). The interaction pattern is modeled after the class
- * [Iterator], in which the method [moveNext] is invoked to move from one result
- * request to the next. The getters [currentResult] and [currentTarget] are used
- * to get the result and target of the current request. The value of the result
- * must be supplied using the [currentValue] setter before [moveNext] can be
- * invoked to move to the next request. When [moveNext] returns `false`,
- * indicating that there are no more requests, the method [inputValue] can be
- * used to access the value of the input that was built.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskInputBuilder<V> {
-  /**
-   * Return the result that needs to be computed, or `null` if [moveNext] has
-   * not been invoked or if the last invocation of [moveNext] returned `false`.
-   */
-  ResultDescriptor get currentResult;
-
-  /**
-   * Return the target for which the result needs to be computed, or `null` if
-   * [moveNext] has not been invoked or if the last invocation of [moveNext]
-   * returned `false`.
-   */
-  AnalysisTarget get currentTarget;
-
-  /**
-   * Set the [value] that was computed for the current result.
-   *
-   * Throws a [StateError] if [moveNext] has not been invoked or if the last
-   * invocation of [moveNext] returned `false`.
-   */
-  void set currentValue(Object value);
-
-  /**
-   * Return `true` if the value accessed by this input builder should be flushed
-   * from the cache at the time it is retrieved.
-   */
-  bool get flushOnAccess;
-
-  /**
-   * Return the [value] that was computed by this builder.
-   *
-   * Throws a [StateError] if [moveNext] has not been invoked or if the last
-   * invocation of [moveNext] returned `true`.
-   *
-   * Returns `null` if no value could be computed due to a circular dependency.
-   */
-  V get inputValue;
-
-  /**
-   * Record that no value is available for the current result, due to a
-   * circular dependency.
-   *
-   * Throws a [StateError] if [moveNext] has not been invoked or if the last
-   * invocation of [moveNext] returned `false`.
-   */
-  void currentValueNotAvailable();
-
-  /**
-   * Move to the next result that needs to be computed in order to build the
-   * inputs for a task. Return `true` if there is another result that needs to
-   * be computed, or `false` if the inputs have been computed.
-   *
-   * It is safe to invoke [moveNext] after it has returned `false`. In this case
-   * [moveNext] has no effect and will again return `false`.
-   *
-   * Throws a [StateError] if the value of the current result has not been
-   * provided using [currentValue].
-   */
-  bool moveNext();
-}
-
-/**
- * An indication of how suitable a task is for a given target.
- */
-enum TaskSuitability { NONE, LOWEST, HIGHEST }
-
-/**
- * [WorkManager]s are used to drive analysis.
- *
- * They know specific of the targets and results they care about,
- * so they can request analysis results in optimal order.
- *
- * Clients may implement this class when implementing plugins.
- */
-abstract class WorkManager {
-  /**
-   * Notifies the manager about changes in the explicit source list.
-   */
-  void applyChange(List<Source> addedSources, List<Source> changedSources,
-      List<Source> removedSources);
-
-  /**
-   * Notifies the managers that the given set of priority [targets] was set.
-   */
-  void applyPriorityTargets(List<AnalysisTarget> targets);
-
-  /**
-   * Return a list of all of the errors associated with the given [source].
-   * The list of errors will be empty if the source is not known to the context
-   * or if there are no errors in the source. The errors contained in the list
-   * can be incomplete.
-   */
-  List<AnalysisError> getErrors(Source source);
-
-  /**
-   * Return the next [TargetedResult] that this work manager wants to be
-   * computed, or `null` if this manager doesn't need any new results.
-   *
-   * Note, that it is not guaranteed that this result will be computed, it is
-   * up to the work manager to check whether the result is already computed
-   * (for example during the next [getNextResult] invocation) or computation
-   * of the same result should be requested again.
-   */
-  TargetedResult getNextResult();
-
-  /**
-   * Return the priority if the next work order this work manager want to be
-   * computed. The [AnalysisDriver] will perform the work order with
-   * the highest priority.
-   *
-   * Even if the returned value is [WorkOrderPriority.NONE], it still does not
-   * guarantee that [getNextResult] will return not `null`.
-   */
-  WorkOrderPriority getNextResultPriority();
-
-  /**
-   * Notifies the manager about analysis options changes.
-   */
-  void onAnalysisOptionsChanged();
-
-  /**
-   * Notifies the manager about [SourceFactory] changes.
-   */
-  void onSourceFactoryChanged();
-
-  /**
-   * Notifies the manager that the given [outputs] were produced for
-   * the given [target].
-   */
-  void resultsComputed(
-      AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs);
-}
-
-/**
- * The priorities of work orders returned by [WorkManager]s.
- *
- * New priorities may be added with time, clients need to tolerate this.
- */
-enum WorkOrderPriority {
-  /**
-   * Responding to an user's action.
-   */
-  INTERACTIVE,
-
-  /**
-   * Computing information for priority sources.
-   */
-  PRIORITY,
-
-  /**
-   * A work should be done, but without any special urgency.
-   */
-  NORMAL,
-
-  /**
-   * Nothing to do.
-   */
-  NONE
-}
diff --git a/pkg/analyzer/lib/src/task/api/yaml.dart b/pkg/analyzer/lib/src/task/api/yaml.dart
deleted file mode 100644
index aacc75d..0000000
--- a/pkg/analyzer/lib/src/task/api/yaml.dart
+++ /dev/null
@@ -1,21 +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.
-
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:yaml/yaml.dart';
-
-/**
- * The result of parsing a YAML file.
- */
-final ResultDescriptor<YamlDocument> YAML_DOCUMENT =
-    new ResultDescriptor<YamlDocument>('YAML_DOCUMENT', null);
-
-/**
- * The analysis errors associated with a [Source] representing a YAML file.
- */
-final ListResultDescriptor<AnalysisError> YAML_ERRORS =
-    new ListResultDescriptor<AnalysisError>(
-        'YAML_ERRORS', AnalysisError.NO_ERRORS);
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
deleted file mode 100644
index 843041d..0000000
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ /dev/null
@@ -1,890 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/inputs.dart';
-import 'package:analyzer/src/task/manager.dart';
-
-final PerformanceTag analysisDriverProcessOutputs =
-    _taskDriverTag.createChild('processOutputs');
-
-final PerformanceTag workOrderMoveNextPerformanceTag =
-    _taskDriverTag.createChild('workOrderMoveNext');
-
-final PerformanceTag _taskDriverTag =
-    PerformanceStatistics.analyzer.createChild('taskDriver');
-
-/**
- * An object that is used to cause analysis to be performed until all of the
- * required analysis information has been computed.
- */
-class AnalysisDriver {
-  /**
-   * The task manager used to figure out how to compute analysis results.
-   */
-  final TaskManager taskManager;
-
-  /**
-   * The list of [WorkManager] used to figure out which analysis results to
-   * compute.
-   */
-  final List<WorkManager> workManagers;
-
-  /**
-   * The context in which analysis is to be performed.
-   */
-  final InternalAnalysisContext context;
-
-  /**
-   * The map of [ResultChangedEvent] controllers.
-   */
-  final Map<ResultDescriptor, StreamController<ResultChangedEvent>>
-      resultComputedControllers =
-      <ResultDescriptor, StreamController<ResultChangedEvent>>{};
-
-  /**
-   * The work order that was previously computed but that has not yet been
-   * completed.
-   */
-  WorkOrder currentWorkOrder;
-
-  /**
-   * Indicates whether any tasks are currently being performed (or building
-   * their inputs).  In debug builds, we use this to ensure that tasks don't
-   * try to make use of the task manager in reentrant fashion.
-   */
-  bool isTaskRunning = false;
-
-  /**
-   * The controller that is notified when a task is started.
-   */
-  StreamController<AnalysisTask> _onTaskStartedController;
-
-  /**
-   * The controller that is notified when a task is complete.
-   */
-  StreamController<AnalysisTask> _onTaskCompletedController;
-
-  /**
-   * Initialize a newly created driver to use the tasks know to the given
-   * [taskManager] to perform analysis in the given [context].
-   */
-  AnalysisDriver(this.taskManager, this.workManagers, this.context) {
-    _onTaskStartedController = new StreamController.broadcast();
-    _onTaskCompletedController = new StreamController.broadcast();
-  }
-
-  /**
-   * The stream that is notified when a task is complete.
-   */
-  Stream<AnalysisTask> get onTaskCompleted => _onTaskCompletedController.stream;
-
-  /**
-   * The stream that is notified when a task is started.
-   */
-  Stream<AnalysisTask> get onTaskStarted => _onTaskStartedController.stream;
-
-  /**
-   * Perform work until the given [result] has been computed for the given
-   * [target]. Return the last [AnalysisTask] that was performed.
-   */
-  AnalysisTask computeResult(AnalysisTarget target, ResultDescriptor result) {
-    assert(!isTaskRunning);
-    try {
-      isTaskRunning = true;
-      AnalysisTask task;
-      while (true) {
-        try {
-          WorkOrder workOrder = createWorkOrderForResult(target, result);
-          if (workOrder != null) {
-            while (workOrder.moveNext()) {
-              task = performWorkItem(workOrder.current);
-            }
-          }
-          break;
-        } on ModificationTimeMismatchError {
-          // Cache inconsistency was detected and fixed by invalidating
-          // corresponding results in cache. Computation must be restarted.
-        }
-      }
-      return task;
-    } finally {
-      isTaskRunning = false;
-    }
-  }
-
-  /**
-   * Return the work order describing the work that should be getting worked on,
-   * or `null` if there is currently no work to be done.
-   */
-  WorkOrder createNextWorkOrder() {
-    while (true) {
-      // Find the WorkManager with the highest priority.
-      WorkOrderPriority highestPriority = null;
-      WorkManager highestManager = null;
-      for (WorkManager manager in workManagers) {
-        WorkOrderPriority priority = manager.getNextResultPriority();
-        if (highestPriority == null || highestPriority.index > priority.index) {
-          highestPriority = priority;
-          highestManager = manager;
-        }
-      }
-      // Nothing to do.
-      if (highestPriority == WorkOrderPriority.NONE) {
-        return null;
-      }
-      // Create a new WorkOrder.
-      TargetedResult request = highestManager.getNextResult();
-//      print('request: $request');
-      if (request != null) {
-        WorkOrder workOrder =
-            createWorkOrderForResult(request.target, request.result);
-        if (workOrder != null) {
-          return workOrder;
-        }
-      }
-    }
-  }
-
-  /**
-   * Create a work order that will produce the given [result] for the given
-   * [target]. Return the work order that was created, or `null` if the result
-   * has either already been computed or cannot be computed.
-   */
-  WorkOrder createWorkOrderForResult(
-      AnalysisTarget target, ResultDescriptor result) {
-    CacheEntry entry = context.getCacheEntry(target);
-    CacheState state = entry.getState(result);
-    if (state == CacheState.VALID ||
-        state == CacheState.ERROR ||
-        state == CacheState.IN_PROCESS) {
-      return null;
-    }
-    if (context.aboutToComputeResult(entry, result)) {
-      return null;
-    }
-    TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
-    if (taskDescriptor == null) {
-      return null;
-    }
-    try {
-      WorkItem workItem =
-          new WorkItem._(context, target, taskDescriptor, result, 0, null);
-      return new WorkOrder(taskManager, workItem);
-    } catch (exception, stackTrace) {
-      throw new AnalysisException(
-          'Could not create work order (target = $target; taskDescriptor = $taskDescriptor; result = $result)',
-          new CaughtException(exception, stackTrace));
-    }
-  }
-
-  /**
-   * Create a work order that will produce the required analysis results for
-   * the given [target]. If [isPriority] is true, then the target is a priority
-   * target. Return the work order that was created, or `null` if there is no
-   * further work that needs to be done for the given target.
-   */
-  WorkOrder createWorkOrderForTarget(AnalysisTarget target, bool isPriority) {
-    for (ResultDescriptor result in taskManager.generalResults) {
-      WorkOrder workOrder = createWorkOrderForResult(target, result);
-      if (workOrder != null) {
-        return workOrder;
-      }
-    }
-    if (isPriority) {
-      for (ResultDescriptor result in taskManager.priorityResults) {
-        WorkOrder workOrder = createWorkOrderForResult(target, result);
-        if (workOrder != null) {
-          return workOrder;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the stream that is notified when a new value for the given
-   * [descriptor] is computed.
-   */
-  Stream<ResultChangedEvent> onResultComputed(ResultDescriptor descriptor) {
-    return resultComputedControllers.putIfAbsent(descriptor, () {
-      return new StreamController<ResultChangedEvent>.broadcast(sync: true);
-    }).stream;
-  }
-
-  /**
-   * Perform the next analysis task, and return `true` if there is more work to
-   * be done in order to compute all of the required analysis information.
-   */
-  bool performAnalysisTask() {
-    //
-    // TODO(brianwilkerson) This implementation does not allow us to prioritize
-    // work across contexts. What we need is a way for an external client to ask
-    // to have all priority files analyzed for each context, then ask for normal
-    // files to be analyzed. There are a couple of ways to do this.
-    //
-    // First, we could add a "bool priorityOnly" parameter to this method and
-    // return null here when it is true.
-    //
-    // Second, we could add a concept of a priority order and (externally) run
-    // through the priorities from highest to lowest. That would be a nice
-    // generalization of the previous idea, but it isn't clear that we need the
-    // generality.
-    //
-    // Third, we could move performAnalysisTask and createNextWorkOrder to an
-    // object that knows about all sources in all contexts, so that instead of
-    // the client choosing a context and telling it do to some work, the client
-    // simply says "do some work", and the engine chooses the best thing to do
-    // next regardless of what context it's in.
-    //
-    assert(!isTaskRunning);
-    try {
-      isTaskRunning = true;
-      if (currentWorkOrder == null) {
-        currentWorkOrder = createNextWorkOrder();
-      } else if (currentWorkOrder.moveNext()) {
-        try {
-          performWorkItem(currentWorkOrder.current);
-        } on ModificationTimeMismatchError {
-          reset();
-          return true;
-        }
-      } else {
-        currentWorkOrder = createNextWorkOrder();
-      }
-      return currentWorkOrder != null;
-    } finally {
-      isTaskRunning = false;
-    }
-  }
-
-  /**
-   * Perform the given work item.
-   * Return the performed [AnalysisTask].
-   */
-  AnalysisTask performWorkItem(WorkItem item) {
-    if (item.exception != null) {
-      // Mark all of the results that the task would have computed as being in
-      // ERROR with the exception recorded on the work item.
-      CacheEntry targetEntry = context.getCacheEntry(item.target);
-      targetEntry.setErrorState(item.exception, item.descriptor.results);
-      return null;
-    }
-    // Otherwise, perform the task.
-    AnalysisTask task = item.buildTask();
-    _onTaskStartedController.add(task);
-    task.perform();
-    analysisDriverProcessOutputs.makeCurrentWhile(() {
-      AnalysisTarget target = task.target;
-      CacheEntry entry = context.getCacheEntry(target);
-      if (task.caughtException == null) {
-        List<TargetedResult> dependedOn =
-            context.analysisOptions.trackCacheDependencies
-                ? item.inputTargetedResults.toList()
-                : const <TargetedResult>[];
-        Map<ResultDescriptor, dynamic> outputs = task.outputs;
-        List<ResultDescriptor> results = task.descriptor.results;
-        int resultLength = results.length;
-        for (int i = 0; i < resultLength; i++) {
-          ResultDescriptor result = results[i];
-          // TODO(brianwilkerson) We could check here that a value was produced
-          // and throw an exception if not (unless we want to allow null values).
-          entry.setValue(result, outputs[result], dependedOn);
-        }
-        outputs.forEach((ResultDescriptor descriptor, value) {
-          StreamController<ResultChangedEvent> controller =
-              resultComputedControllers[descriptor];
-          if (controller != null) {
-            ResultChangedEvent event = new ResultChangedEvent(
-                context, target, descriptor, value, true);
-            controller.add(event);
-          }
-        });
-        for (WorkManager manager in workManagers) {
-          manager.resultsComputed(target, outputs);
-        }
-      } else {
-        entry.setErrorState(task.caughtException, item.descriptor.results);
-      }
-    });
-    _onTaskCompletedController.add(task);
-    return task;
-  }
-
-  /**
-   * Reset the state of the driver in response to a change in the state of one
-   * or more analysis targets. This will cause any analysis that was currently
-   * in process to be stopped and for analysis to resume based on the new state.
-   */
-  void reset() {
-    currentWorkOrder = null;
-  }
-}
-
-/**
- * Generic dependency walker suitable for use in the analysis task driver.
- * This class implements a variant of the path-based strong component algorithm
- * (described here: http://www.cs.colorado.edu/~hal/Papers/DFS/ipl.ps.gz), with
- * the following differences:
- *
- * - The algorithm is non-recursive so that it can be used in a coroutine
- *   fashion (each call to [getNextStronglyConnectedComponent] computes a
- *   single strongly connected component and then waits to be called again)
- *
- * - Instead of keeping a temporary array which maps nodes to their locations
- *   in the [path] array, we simply search the array when necessary.  This
- *   allows us to begin finding strongly connected components without having to
- *   know the size of the whole graph.
- *
- * - This algorithm does not compute all strongly connected components; only
- *   those reachable from the starting point which are as yet unevaluated.
- *
- * The algorithm, in essence, is to traverse the dependency graph in
- * depth-first fashion from a starting node.  If the path from the starting
- * node ever encounters the same node twice, then a cycle has been found, and
- * all the nodes comprising the cycle are (conceptually) contracted into a
- * single node.  The algorithm yields possibly-collapsed nodes in proper
- * topological sort order (all the dependencies of a node are yielded before,
- * or in the same contracted component as, the node itself).
- */
-abstract class CycleAwareDependencyWalker<Node> {
-  /**
-   * The path through the dependency graph that is currently being considered,
-   * with un-collapsed nodes.
-   */
-  final List<Node> _path;
-
-  /**
-   * For each node in [_path], a list of the unevaluated nodes which it is
-   * already known to depend on.
-   */
-  final List<List<Node>> _provisionalDependencies;
-
-  /**
-   * Indices into [_path] of the nodes which begin a new strongly connected
-   * component, in order.  The first index in [_contractedPath] is always 0.
-   *
-   * For all i < contractedPath.length - 1, at least one node in the strongly
-   * connected component represented by [contractedPath[i]] depends directly
-   * on at least one node in the strongly connected component represented by
-   * [contractedPath[i+1]].
-   */
-  final List<int> _contractedPath;
-
-  /**
-   * Index into [_path] of the nodes which we are currently in the process of
-   * querying for their dependencies.
-   *
-   * [currentIndices.last] always refers to a member of the last strongly
-   * connected component indicated by [_contractedPath].
-   */
-  final List<int> _currentIndices;
-
-  /**
-   * Begin walking dependencies starting at [startingNode].
-   */
-  CycleAwareDependencyWalker(Node startingNode)
-      : _path = <Node>[startingNode],
-        _provisionalDependencies = <List<Node>>[<Node>[]],
-        _contractedPath = <int>[0],
-        _currentIndices = <int>[0];
-
-  /**
-   * Determine the next unevaluated input for [node], skipping any inputs in
-   * [skipInputs], and return it.  If [node] has no further inputs, return
-   * `null`.
-   */
-  Node getNextInput(Node node, List<Node> skipInputs);
-
-  /**
-   * Determine the next strongly connected component in the graph, and return
-   * it.  The client is expected to evaluate this component before calling
-   * [getNextStronglyConnectedComponent] again.
-   */
-  StronglyConnectedComponent<Node> getNextStronglyConnectedComponent() {
-    while (_currentIndices.isNotEmpty) {
-      Node nextUnevaluatedInput = getNextInput(_path[_currentIndices.last],
-          _provisionalDependencies[_currentIndices.last]);
-      // If the assertion below fails, it indicates that [getNextInput] did not
-      // skip an input that we asked it to skip.
-      assert(!_provisionalDependencies[_currentIndices.last]
-          .contains(nextUnevaluatedInput));
-      if (nextUnevaluatedInput != null) {
-        // TODO(paulberry): the call to _path.indexOf makes the algorithm
-        // O(n^2) in the depth of the dependency graph.  If this becomes a
-        // problem, consider maintaining a map from node to index.
-        int previousIndex = _path.indexOf(nextUnevaluatedInput);
-        if (previousIndex != -1) {
-          // Update contractedPath to indicate that all nodes in the path
-          // between previousIndex and currentIndex are part of the same
-          // strongly connected component.
-          while (_contractedPath.last > previousIndex) {
-            _contractedPath.removeLast();
-          }
-          // Store nextUnevaluatedInput as a provisional dependency so that we
-          // can move on to computing other dependencies.
-          _provisionalDependencies[_currentIndices.last]
-              .add(nextUnevaluatedInput);
-          // And loop to move on to the node's next input.
-          continue;
-        } else {
-          // This is a brand new input and there's no reason (yet) to believe
-          // that it is in the same strongly connected component as any other
-          // node, so push it onto the end of the path.
-          int newIndex = _path.length;
-          _path.add(nextUnevaluatedInput);
-          _provisionalDependencies.add(<Node>[]);
-          _contractedPath.add(newIndex);
-          _currentIndices.add(newIndex);
-          // And loop to move on to the new node's inputs.
-          continue;
-        }
-      } else {
-        // The node has no more inputs.  Figure out if there are any more nodes
-        // in the current strongly connected component that need to have their
-        // indices examined.
-        _currentIndices.removeLast();
-        if (_currentIndices.isEmpty ||
-            _currentIndices.last < _contractedPath.last) {
-          // No more nodes in the current strongly connected component need to
-          // have their indices examined.  We can now yield this component to
-          // the caller.
-          List<Node> nodes = _path.sublist(_contractedPath.last);
-          bool containsCycle = nodes.length > 1;
-          if (!containsCycle) {
-            if (_provisionalDependencies.last.isNotEmpty) {
-              containsCycle = true;
-            }
-          }
-          _path.length = _contractedPath.last;
-          _provisionalDependencies.length = _contractedPath.last;
-          _contractedPath.removeLast();
-          return new StronglyConnectedComponent<Node>(nodes, containsCycle);
-        } else {
-          // At least one node in the current strongly connected component
-          // still needs to have its inputs examined.  So loop and allow the
-          // inputs to be examined.
-          continue;
-        }
-      }
-    }
-    // No further strongly connected components found.
-    return null;
-  }
-}
-
-/**
- * A place to define the behaviors that need to be added to
- * [InternalAnalysisContext].
- */
-abstract class ExtendedAnalysisContext implements InternalAnalysisContext {
-  List<AnalysisTarget> get explicitTargets;
-  List<AnalysisTarget> get priorityTargets;
-  void set typeProvider(TypeProvider typeProvider);
-  CacheEntry getCacheEntry(AnalysisTarget target);
-}
-
-/**
- * An exception indicating that an attempt was made to perform a task on a
- * target while gathering the inputs to perform the same task for the same
- * target.
- */
-class InfiniteTaskLoopException extends AnalysisException {
-  /**
-   * A concrete cyclic path of [TargetedResults] within the [dependencyCycle],
-   * `null` if no such path exists.  All nodes in the path are in the
-   * dependencyCycle, but the path is not guaranteed to cover the
-   * entire cycle.
-   */
-  final List<TargetedResult> cyclicPath;
-
-  /**
-   * If a dependency cycle was found while computing the inputs for the task,
-   * the set of [WorkItem]s contained in the cycle (if there are overlapping
-   * cycles, this is the set of all [WorkItem]s in the entire strongly
-   * connected component).  Otherwise, `null`.
-   */
-  final List<WorkItem> dependencyCycle;
-
-  /**
-   * Initialize a newly created exception to represent a failed attempt to
-   * perform the given [task] due to the given [dependencyCycle].
-   */
-  InfiniteTaskLoopException(AnalysisTask task, List<WorkItem> dependencyCycle,
-      [List<TargetedResult> cyclicPath])
-      : this.dependencyCycle = dependencyCycle,
-        this.cyclicPath = cyclicPath,
-        super(_composeMessage(task, dependencyCycle, cyclicPath));
-
-  /**
-   * Compose an error message based on the data we have available.
-   */
-  static String _composeMessage(AnalysisTask task,
-      List<WorkItem> dependencyCycle, List<TargetedResult> cyclicPath) {
-    StringBuffer buffer = new StringBuffer();
-    buffer.write('Infinite loop while performing task ');
-    buffer.write(task.descriptor.name);
-    buffer.write(' for ');
-    buffer.writeln(task.target);
-    buffer.writeln('  Dependency Cycle:');
-    for (WorkItem item in dependencyCycle) {
-      buffer.write('    ');
-      buffer.writeln(item);
-    }
-    if (cyclicPath != null) {
-      buffer.writeln('  Cyclic Path:');
-      for (TargetedResult result in cyclicPath) {
-        buffer.write('    ');
-        buffer.writeln(result);
-      }
-    }
-    return buffer.toString();
-  }
-}
-
-/**
- * Object used by [CycleAwareDependencyWalker] to report a single strongly
- * connected component of nodes.
- */
-class StronglyConnectedComponent<Node> {
-  /**
-   * The nodes contained in the strongly connected component.
-   */
-  final List<Node> nodes;
-
-  /**
-   * Indicates whether the strongly component contains any cycles.  Note that
-   * if [nodes] has multiple elements, this will always be `true`.  However, if
-   * [nodes] has exactly one element, this may be either `true` or `false`
-   * depending on whether the node has a dependency on itself.
-   */
-  final bool containsCycle;
-
-  StronglyConnectedComponent(this.nodes, this.containsCycle);
-}
-
-/**
- * A description of a single analysis task that can be performed to advance
- * analysis.
- */
-class WorkItem {
-  /**
-   * The context in which the task will be performed.
-   */
-  final InternalAnalysisContext context;
-
-  /**
-   * The target for which a task is to be performed.
-   */
-  final AnalysisTarget target;
-
-  /**
-   * A description of the task to be performed.
-   */
-  final TaskDescriptor descriptor;
-
-  /**
-   * The [ResultDescriptor] which was led to this work item being spawned.
-   */
-  final ResultDescriptor spawningResult;
-
-  /**
-   * The level of this item in its [WorkOrder].
-   */
-  final int level;
-
-  /**
-   * The work order that this item is part of, may be `null`.
-   */
-  WorkOrder workOrder;
-
-  /**
-   * An iterator used to iterate over the descriptors of the inputs to the task,
-   * or `null` if all of the inputs have been collected and the task can be
-   * created.
-   */
-  TopLevelTaskInputBuilder builder;
-
-  /**
-   * The [TargetedResult]s outputs of this task depends on.
-   */
-  final HashSet<TargetedResult> inputTargetedResults =
-      new HashSet<TargetedResult>();
-
-  /**
-   * The inputs to the task that have been computed.
-   */
-  Map<String, dynamic> inputs = const <String, dynamic>{};
-
-  /**
-   * The exception that was found while trying to populate the inputs. If this
-   * field is non-`null`, then the task cannot be performed and all of the
-   * results that this task would have computed need to be marked as being in
-   * ERROR with this exception.
-   */
-  CaughtException exception = null;
-
-  /**
-   * If a dependency cycle was found while computing the inputs for the task,
-   * the set of [WorkItem]s contained in the cycle (if there are overlapping
-   * cycles, this is the set of all [WorkItem]s in the entire strongly
-   * connected component).  Otherwise, `null`.
-   */
-  List<WorkItem> dependencyCycle;
-
-  /**
-   * Initialize a newly created work item to compute the inputs for the task
-   * described by the given descriptor.
-   */
-  WorkItem._(this.context, this.target, this.descriptor, this.spawningResult,
-      this.level, this.workOrder) {
-    _checkInternalUseOfTaskModel();
-    AnalysisTarget actualTarget =
-        identical(target, AnalysisContextTarget.request)
-            ? new AnalysisContextTarget(context)
-            : target;
-//    print('${'\t' * level}$spawningResult of $actualTarget');
-    Map<String, TaskInput> inputDescriptors =
-        descriptor.createTaskInputs(actualTarget);
-    builder = new TopLevelTaskInputBuilder(inputDescriptors);
-    if (!builder.moveNext()) {
-      builder = null;
-    }
-  }
-
-  @override
-  int get hashCode =>
-      JenkinsSmiHash.hash2(descriptor.hashCode, target.hashCode);
-
-  @override
-  bool operator ==(other) {
-    if (other is WorkItem) {
-      return this.descriptor == other.descriptor && this.target == other.target;
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   * Build the task represented by this work item.
-   */
-  AnalysisTask buildTask() {
-    if (builder != null) {
-      throw new StateError("some inputs have not been computed");
-    }
-    AnalysisTask task = descriptor.createTask(context, target, inputs);
-    task.dependencyCycle = dependencyCycle;
-    return task;
-  }
-
-  /**
-   * Gather all of the inputs needed to perform the task.
-   *
-   * If at least one of the inputs have not yet been computed, return a work
-   * item that can be used to generate that input to indicate that the caller
-   * should perform the returned item's task before returning to gathering
-   * inputs for this item's task.
-   *
-   * If all of the inputs have been gathered, return `null` to indicate that the
-   * client should build and perform the task. A value of `null` will also be
-   * returned if some of the inputs cannot be computed and the task cannot be
-   * performed. Callers can differentiate between these cases by checking the
-   * [exception] field. If the field is `null`, then the task can be performed;
-   * if the field is non-`null` then the task cannot be performed and all of the
-   * tasks' results should be marked as being in ERROR.
-   */
-  WorkItem gatherInputs(TaskManager taskManager, List<WorkItem> skipInputs) {
-    while (builder != null) {
-      AnalysisTarget inputTarget = builder.currentTarget;
-      ResultDescriptor inputResult = builder.currentResult;
-
-      // TODO(scheglov) record information to debug
-      // https://github.com/dart-lang/sdk/issues/24939
-      if (inputTarget == null || inputResult == null) {
-        try {
-          String message =
-              'Invalid input descriptor ($inputTarget, $inputResult) for $this';
-          if (workOrder != null) {
-            message += '\nPath:\n' + workOrder.workItems.join('|\n');
-          }
-          throw new AnalysisException(message);
-        } catch (exception, stackTrace) {
-          this.exception = new CaughtException(exception, stackTrace);
-          AnalysisEngine.instance.logger
-              .logError('Task failed: $this', this.exception);
-        }
-        return null;
-      }
-
-      inputTargetedResults.add(new TargetedResult(inputTarget, inputResult));
-      CacheEntry inputEntry = context.getCacheEntry(inputTarget);
-      CacheState inputState = inputEntry.getState(inputResult);
-      if (inputState == CacheState.ERROR) {
-        exception = inputEntry.exception;
-        return null;
-      } else if (inputState == CacheState.IN_PROCESS) {
-        //
-        // TODO(brianwilkerson) Implement this case.
-        //
-        // One possibility would be to return a WorkItem that would perform a
-        // no-op task in order to cause us to come back to this work item on the
-        // next iteration. It would be more efficient, in general, to push this
-        // input onto a waiting list and proceed to the next input so that work
-        // could proceed, but given that the only result that can currently be
-        // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort
-        // to implement the general solution at this point.
-        //
-        throw new UnimplementedError();
-      } else if (inputState != CacheState.VALID) {
-        if (context.aboutToComputeResult(inputEntry, inputResult)) {
-          inputState = CacheState.VALID;
-          builder.currentValue = inputEntry.getValue(inputResult);
-        } else {
-          try {
-            TaskDescriptor descriptor =
-                taskManager.findTask(inputTarget, inputResult);
-            if (descriptor == null) {
-              throw new AnalysisException(
-                  'Cannot find task to build $inputResult for $inputTarget');
-            }
-            if (skipInputs.any((WorkItem item) =>
-                item.target == inputTarget && item.descriptor == descriptor)) {
-              // This input is being skipped due to a circular dependency.  Tell
-              // the builder that it's not available so we can move on to other
-              // inputs.
-              builder.currentValueNotAvailable();
-            } else {
-              return new WorkItem._(context, inputTarget, descriptor,
-                  inputResult, level + 1, workOrder);
-            }
-          } on AnalysisException catch (exception, stackTrace) {
-            this.exception = new CaughtException(exception, stackTrace);
-            return null;
-          } catch (exception, stackTrace) {
-            this.exception = new CaughtException(exception, stackTrace);
-            throw new AnalysisException(
-                'Cannot create work order to build $inputResult for $inputTarget',
-                this.exception);
-          }
-        }
-      } else {
-        builder.currentValue = inputEntry.getValue(inputResult);
-        if (builder.flushOnAccess) {
-          inputEntry.setState(inputResult, CacheState.FLUSHED);
-        }
-      }
-      if (!builder.moveNext()) {
-        inputs = builder.inputValue;
-        builder = null;
-      }
-    }
-    return null;
-  }
-
-  @override
-  String toString() => 'Run $descriptor on $target';
-
-  static void _checkInternalUseOfTaskModel() {
-    if (!StackTrace.current.toString().contains('/analyzer/test/')) {
-      throw new StateError(
-          'The analyzer task model is no longer supported.  Please use the AnalysisSession API.');
-    }
-  }
-}
-
-/**
- * A description of the work to be done to compute a desired analysis result.
- * The class implements a lazy depth-first traversal of the work item's input.
- */
-class WorkOrder implements Iterator<WorkItem> {
-  /**
-   * The dependency walker which is being used to determine what work to do
-   * next.
-   */
-  final _WorkOrderDependencyWalker _dependencyWalker;
-
-  /**
-   * The strongly connected component most recently returned by
-   * [_dependencyWalker], minus any [WorkItem]s that the iterator has already
-   * moved past.
-   *
-   * Null if the [_dependencyWalker] hasn't been used yet.
-   */
-  List<WorkItem> currentItems;
-
-  /**
-   * Initialize a newly created work order to compute the result described by
-   * the given work item.
-   */
-  WorkOrder(TaskManager taskManager, WorkItem item)
-      : _dependencyWalker = new _WorkOrderDependencyWalker(taskManager, item) {
-    item.workOrder = this;
-  }
-
-  @override
-  WorkItem get current {
-    if (currentItems == null) {
-      return null;
-    } else {
-      return currentItems.last;
-    }
-  }
-
-  List<WorkItem> get workItems => _dependencyWalker._path;
-
-  @override
-  bool moveNext() {
-    return workOrderMoveNextPerformanceTag.makeCurrentWhile(() {
-      if (currentItems != null && currentItems.length > 1) {
-        // Yield more items.
-        currentItems.removeLast();
-        return true;
-      } else {
-        // Get a new strongly connected component.
-        StronglyConnectedComponent<WorkItem> nextStronglyConnectedComponent =
-            _dependencyWalker.getNextStronglyConnectedComponent();
-        if (nextStronglyConnectedComponent == null) {
-          currentItems = null;
-          return false;
-        }
-        currentItems = nextStronglyConnectedComponent.nodes;
-        if (nextStronglyConnectedComponent.containsCycle) {
-          // A cycle has been found.
-          for (WorkItem item in currentItems) {
-            item.dependencyCycle = currentItems.toList();
-          }
-        } else {
-          assert(currentItems.length == 1);
-        }
-        return true;
-      }
-    });
-  }
-}
-
-/**
- * Specialization of [CycleAwareDependencyWalker] for use by [WorkOrder].
- */
-class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> {
-  /**
-   * The task manager used to build work items.
-   */
-  final TaskManager taskManager;
-
-  _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode)
-      : super(startingNode);
-
-  @override
-  WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) {
-    return node.gatherInputs(taskManager, skipInputs);
-  }
-}
diff --git a/pkg/analyzer/lib/src/task/general.dart b/pkg/analyzer/lib/src/task/general.dart
deleted file mode 100644
index 5fcb776..0000000
--- a/pkg/analyzer/lib/src/task/general.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A task that gets the contents of the source associated with an analysis
- * target.
- */
-class GetContentTask extends SourceBasedAnalysisTask {
-  /**
-   * The task descriptor describing this kind of task.
-   */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('GetContentTask',
-      createTask, buildInputs, <ResultDescriptor>[CONTENT, MODIFICATION_TIME]);
-
-  /**
-   * Initialize a newly created task to access the content of the source
-   * associated with the given [target] in the given [context].
-   */
-  GetContentTask(AnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  internalPerform() {
-    Source source = getRequiredSource();
-    String content;
-    int modificationTime;
-    try {
-      TimestampedData<String> data = context.getContents(source);
-      content = data.data;
-      modificationTime = data.modificationTime;
-    } catch (exception) {
-      content = '';
-      modificationTime = -1;
-    }
-    _validateModificationTime(source, modificationTime);
-    outputs[CONTENT] = content;
-    outputs[MODIFICATION_TIME] = modificationTime;
-  }
-
-  /**
-   * Validate that the [target] cache entry has the same modification time
-   * as the given.  Otherwise throw a new [ModificationTimeMismatchError] and
-   * instruct to invalidate targets content.
-   */
-  void _validateModificationTime(Source source, int modificationTime) {
-    AnalysisContext context = this.context;
-    if (context is InternalAnalysisContext) {
-      CacheEntry entry = context.getCacheEntry(target);
-      if (entry != null && entry.modificationTime != modificationTime) {
-        entry.modificationTime = modificationTime;
-        entry.setState(CONTENT, CacheState.INVALID);
-        entry.setState(MODIFICATION_TIME, CacheState.INVALID);
-        throw new ModificationTimeMismatchError(source);
-      }
-    }
-  }
-
-  /**
-   * Return a map from the names of the inputs of this kind of task to the task
-   * input descriptors describing those inputs for a task with the given [target].
-   */
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    return <String, TaskInput>{};
-  }
-
-  /**
-   * Create a [GetContentTask] based on the given [target] in the given
-   * [context].
-   */
-  static GetContentTask createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new GetContentTask(context, target);
-  }
-}
-
-/**
- * A base class for analysis tasks whose target is expected to be a source.
- */
-abstract class SourceBasedAnalysisTask extends AnalysisTask {
-  /**
-   * Initialize a newly created task to perform analysis within the given
-   * [context] in order to produce results for the given [target].
-   */
-  SourceBasedAnalysisTask(AnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  String get description {
-    Source source = target.source;
-    String sourceName = source == null ? '<unknown source>' : source.fullName;
-    return '${descriptor.name} for source $sourceName';
-  }
-}
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
deleted file mode 100644
index 30fd2446e..0000000
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ /dev/null
@@ -1,998 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:collection';
-
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A function that converts an object of the type [B] into a [TaskInput].
- * This is used, for example, by a [ListToListTaskInput] to create task inputs
- * for each value in a list of values.
- */
-typedef TaskInput<E> GenerateTaskInputs<B, E>(B object);
-
-/**
- * A function that maps one [value] to another value.
- */
-typedef R Mapper<P, R>(P value);
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class ConstantTaskInput<V> extends TaskInputImpl<V> {
-  final V value;
-
-  ConstantTaskInput(this.value);
-
-  @override
-  TaskInputBuilder<V> createBuilder() {
-    return new ConstantTaskInputBuilder<V>(this);
-  }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ConstantTaskInput].
- */
-class ConstantTaskInputBuilder<V> implements TaskInputBuilder<V> {
-  final ConstantTaskInput<V> input;
-
-  ConstantTaskInputBuilder(this.input);
-
-  @override
-  ResultDescriptor get currentResult => null;
-
-  @override
-  AnalysisTarget get currentTarget => null;
-
-  @override
-  void set currentValue(Object value) {
-    throw new StateError('Only supported after moveNext() returns true');
-  }
-
-  @override
-  bool get flushOnAccess => false;
-
-  @override
-  V get inputValue => input.value;
-
-  @override
-  void currentValueNotAvailable() {
-    throw new StateError('Only supported after moveNext() returns true');
-  }
-
-  @override
-  bool moveNext() => false;
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
-    with ListTaskInputMixin<E>
-    implements ListTaskInput<E> {
-  /**
-   * Initialize a newly created task input that computes the input by accessing
-   * the given [result] associated with the given [target].
-   */
-  ListTaskInputImpl(AnalysisTarget target, ResultDescriptor<List<E>> result)
-      : super._unflushable(target, result);
-}
-
-/**
- * A mixin-ready implementation of [ListTaskInput].
- */
-abstract class ListTaskInputMixin<E> implements ListTaskInput<E> {
-  @override
-  ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult) {
-    return new ListToFlattenListTaskInput<E, V>(
-        this,
-        (E element) =>
-            subListResult.of(element as AnalysisTarget) as TaskInput<V>);
-  }
-
-  ListTaskInput<V> toList<V>(UnaryFunction<E, V> mapper) {
-    return new ListToListTaskInput<E, V>(this, mapper);
-  }
-
-  ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult) {
-    return (this as ListTaskInput<AnalysisTarget>).toList(valueResult.of);
-  }
-
-  MapTaskInput<E, V> toMap<V>(UnaryFunction<E, V> mapper) {
-    return new ListToMapTaskInput<E, V>(this, mapper);
-  }
-
-  MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult) {
-    return (this as ListTaskInputImpl<AnalysisTarget>).toMap<V>(valueResult.of);
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the list of the analysis results is used as the input to the task.
- */
-class ListToFlattenListTaskInput<B, E>
-    extends _ListToCollectionTaskInput<B, E, List<E>>
-    with ListTaskInputMixin<E>
-    implements ListTaskInput<E> {
-  /**
-   * Initialize a result accessor to use the given [baseAccessor] to access a
-   * list of values that can be passed to the given [generateTaskInputs] to
-   * generate a list of task inputs that can be used to access the elements of
-   * the input being accessed.
-   */
-  ListToFlattenListTaskInput(TaskInput<List<B>> baseAccessor,
-      GenerateTaskInputs<B, E> generateTaskInputs)
-      : super(baseAccessor, generateTaskInputs);
-
-  @override
-  TaskInputBuilder<List<E>> createBuilder() =>
-      new ListToFlattenListTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToFlattenListTaskInput].
- */
-class ListToFlattenListTaskInputBuilder<B, E>
-    extends _ListToCollectionTaskInputBuilder<B, E, List<E>> {
-  /**
-   * The list of values being built.
-   */
-  List<E> _resultValue;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  ListToFlattenListTaskInputBuilder(ListToFlattenListTaskInput<B, E> input)
-      : super(input);
-
-  @override
-  void _addResultElement(B baseElement, E resultElement) {
-    _resultValue.addAll(resultElement as Iterable<E>);
-  }
-
-  @override
-  void _initResultValue() {
-    _resultValue = <E>[];
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the list of the analysis results is used as the input to the task.
- */
-class ListToListTaskInput<B, E>
-    extends _ListToCollectionTaskInput<B, E, List<E>>
-    with ListTaskInputMixin<E> {
-  /**
-   * Initialize a result accessor to use the given [baseAccessor] to access a
-   * list of values that can be passed to the given [generateTaskInputs] to
-   * generate a list of task inputs that can be used to access the elements of
-   * the input being accessed.
-   */
-  ListToListTaskInput(TaskInput<List<B>> baseAccessor,
-      GenerateTaskInputs<B, E> generateTaskInputs)
-      : super(baseAccessor, generateTaskInputs);
-
-  @override
-  TaskInputBuilder<List<E>> createBuilder() =>
-      new ListToListTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToListTaskInput].
- */
-class ListToListTaskInputBuilder<B, E>
-    extends _ListToCollectionTaskInputBuilder<B, E, List<E>> {
-  /**
-   * The list of values being built.
-   */
-  List<E> _resultValue;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  ListToListTaskInputBuilder(ListToListTaskInput<B, E> input) : super(input);
-
-  @override
-  void _addResultElement(B baseElement, E resultElement) {
-    _resultValue.add(resultElement);
-  }
-
-  @override
-  void _initResultValue() {
-    _resultValue = <E>[];
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the map of the base elements to the analysis results is used as the
- * input to the task.
- */
-class ListToMapTaskInput<B, E>
-    extends _ListToCollectionTaskInput<B, E, Map<B, E>>
-    with MapTaskInputMixin<B, E> {
-  /**
-   * Initialize a result accessor to use the given [baseAccessor] to access a
-   * list of values that can be passed to the given [generateTaskInputs] to
-   * generate a list of task inputs that can be used to access the elements of
-   * the input being accessed.
-   */
-  ListToMapTaskInput(TaskInput<List<B>> baseAccessor,
-      GenerateTaskInputs<B, E> generateTaskInputs)
-      : super(baseAccessor, generateTaskInputs);
-
-  @override
-  TaskInputBuilder<Map<B, E>> createBuilder() =>
-      new ListToMapTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToMapTaskInput].
- */
-class ListToMapTaskInputBuilder<B, E>
-    extends _ListToCollectionTaskInputBuilder<B, E, Map<B, E>> {
-  /**
-   * The map being built.
-   */
-  Map<B, E> _resultValue;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  ListToMapTaskInputBuilder(ListToMapTaskInput<B, E> input) : super(input);
-
-  @override
-  void _addResultElement(B baseElement, E resultElement) {
-    _resultValue[baseElement] = resultElement;
-  }
-
-  @override
-  void _initResultValue() {
-    _resultValue = new HashMap<B, E>();
-  }
-}
-
-/**
- * A mixin-ready implementation of [MapTaskInput].
- */
-abstract class MapTaskInputMixin<K, V> implements MapTaskInput<K, V> {
-  TaskInput<List<E>> toFlattenList<E>(
-      BinaryFunction<K, dynamic /*element of V*/, E> mapper) {
-    return new MapToFlattenListTaskInput<K, dynamic /*element of V*/, E>(
-        this as MapTaskInput<K, List /*element of V*/ >, mapper);
-  }
-}
-
-/**
- * A [TaskInput] that is computed by the following steps.
- *
- * First the [base] task input is used to compute a [Map]-valued result.
- * The values of the [Map] must be [List]s.
- *
- * The given [mapper] is used to transform each key / value pair of the [Map]
- * into task inputs.
- *
- * Finally, each of the task inputs are used to access analysis results,
- * and the list of the results is used as the input.
- */
-class MapToFlattenListTaskInput<K, V, E> extends TaskInputImpl<List<E>> {
-  final MapTaskInput<K, List<V>> base;
-  final BinaryFunction<K, V, E> mapper;
-
-  MapToFlattenListTaskInput(this.base, this.mapper);
-
-  @override
-  TaskInputBuilder<List<E>> createBuilder() {
-    return new MapToFlattenListTaskInputBuilder<K, V, E>(base, mapper);
-  }
-}
-
-/**
- * The [TaskInputBuilder] for [MapToFlattenListTaskInput].
- */
-class MapToFlattenListTaskInputBuilder<K, V, E>
-    implements TaskInputBuilder<List<E>> {
-  final MapTaskInput<K, List<V>> base;
-  final BinaryFunction<K, V, E> mapper;
-
-  TaskInputBuilder currentBuilder;
-  Map<K, List<V>> baseMap;
-  Iterator<K> keyIterator;
-  Iterator<V> valueIterator;
-
-  final List<E> inputValue = <E>[];
-
-  MapToFlattenListTaskInputBuilder(this.base, this.mapper) {
-    currentBuilder = base.createBuilder();
-  }
-
-  @override
-  ResultDescriptor get currentResult {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentResult;
-  }
-
-  AnalysisTarget get currentTarget {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentTarget;
-  }
-
-  @override
-  void set currentValue(Object value) {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValue = value;
-  }
-
-  @override
-  bool get flushOnAccess => currentBuilder.flushOnAccess;
-
-  @override
-  void currentValueNotAvailable() {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValueNotAvailable();
-  }
-
-  @override
-  bool moveNext() {
-    // Prepare base Map.
-    if (baseMap == null) {
-      if (currentBuilder.moveNext()) {
-        return true;
-      }
-      baseMap = currentBuilder.inputValue as Map<K, List<V>>;
-      if (baseMap == null) {
-        // No base map could be computed due to a circular dependency.  Use an
-        // empty map so that no further results will be computed.
-        baseMap = {};
-      }
-      keyIterator = baseMap.keys.iterator;
-      // Done with this builder.
-      currentBuilder = null;
-    }
-    // Prepare the next result value.
-    if (currentBuilder != null) {
-      if (currentBuilder.moveNext()) {
-        return true;
-      }
-      // Add the result value for the current Map key/value.
-      E resultValue = currentBuilder.inputValue as E;
-      if (resultValue != null) {
-        inputValue.add(resultValue);
-      }
-      // Done with this builder.
-      currentBuilder = null;
-    }
-    // Move to the next Map value.
-    if (valueIterator != null && valueIterator.moveNext()) {
-      K key = keyIterator.current;
-      V value = valueIterator.current;
-      currentBuilder = mapper(key, value).createBuilder();
-      return moveNext();
-    }
-    // Move to the next Map key.
-    if (keyIterator.moveNext()) {
-      K key = keyIterator.current;
-      valueIterator = baseMap[key].iterator;
-      return moveNext();
-    }
-    // No more Map values/keys to transform.
-    return false;
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by mapping the value of
- * another task input to a list of values.
- */
-class ObjectToListTaskInput<E> extends TaskInputImpl<List<E>>
-    with ListTaskInputMixin<E>
-    implements ListTaskInput<E> {
-  // TODO(brianwilkerson) Add another type parameter to this class that can be
-  // used as the type of the keys of [mapper].
-  /**
-   * The input used to compute the value to be mapped.
-   */
-  final TaskInput baseInput;
-
-  /**
-   * The function used to map the value of the base input to the list of values.
-   */
-  final Mapper<Object, List<E>> mapper;
-
-  /**
-   * Initialize a newly created task input that computes the input by accessing
-   * the given [baseInput] associated with the given [mapper].
-   */
-  ObjectToListTaskInput(this.baseInput, this.mapper);
-
-  @override
-  TaskInputBuilder<List<E>> createBuilder() =>
-      new ObjectToListTaskInputBuilder<E>(this);
-
-  @override
-  ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult) {
-    return new ListToFlattenListTaskInput<E, V>(
-        this,
-        (E element) =>
-            subListResult.of(element as AnalysisTarget) as TaskInput<V>);
-  }
-
-  @override
-  ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult) {
-    return new ListToListTaskInput<E, V>(
-        this, (E element) => valueResult.of(element as AnalysisTarget));
-  }
-
-  @override
-  MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult) {
-    return new ListToMapTaskInput<AnalysisTarget, V>(
-        this as TaskInput<List<AnalysisTarget>>, valueResult.of);
-  }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [SimpleTaskInput].
- */
-class ObjectToListTaskInputBuilder<E> implements TaskInputBuilder<List<E>> {
-  /**
-   * The input being built.
-   */
-  final ObjectToListTaskInput<E> input;
-
-  /**
-   * The builder created by the input.
-   */
-  TaskInputBuilder builder;
-
-  /**
-   * The value of the input being built, or `null` if the value hasn't been set
-   * yet or if no result is available ([currentValueNotAvailable] was called).
-   */
-  List<E> _inputValue = null;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  ObjectToListTaskInputBuilder(this.input) {
-    builder = input.baseInput.createBuilder();
-  }
-
-  @override
-  ResultDescriptor get currentResult {
-    if (builder == null) {
-      return null;
-    }
-    return builder.currentResult;
-  }
-
-  @override
-  AnalysisTarget get currentTarget {
-    if (builder == null) {
-      return null;
-    }
-    return builder.currentTarget;
-  }
-
-  @override
-  void set currentValue(Object value) {
-    if (builder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    builder.currentValue = value;
-  }
-
-  @override
-  bool get flushOnAccess => builder.flushOnAccess;
-
-  @override
-  List<E> get inputValue {
-    if (builder != null) {
-      throw new StateError('Result value has not been created');
-    }
-    return _inputValue;
-  }
-
-  @override
-  void currentValueNotAvailable() {
-    if (builder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    builder.currentValueNotAvailable();
-  }
-
-  @override
-  bool moveNext() {
-    if (builder == null) {
-      return false;
-    } else if (builder.moveNext()) {
-      return true;
-    } else {
-      // This might not be the right semantics. If the value could not be
-      // computed then we pass the resulting `null` in to the mapper function.
-      // Unfortunately, we cannot tell the difference between a `null` that's
-      // there because no value could be computed and a `null` that's there
-      // because that's what *was* computed.
-      _inputValue = input.mapper(builder.inputValue);
-      builder = null;
-      return false;
-    }
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class SimpleTaskInput<V> extends TaskInputImpl<V> {
-  /**
-   * The target on which the result is defined.
-   */
-  final AnalysisTarget target;
-
-  /**
-   * The result to be accessed.
-   */
-  final ResultDescriptor<V> result;
-
-  /**
-   * Return `true` if the value accessed by this input builder should be flushed
-   * from the cache at the time it is retrieved.
-   */
-  final bool flushOnAccess;
-
-  /**
-   * Initialize a newly created task input that computes the input by accessing
-   * the given [result] associated with the given [target].
-   */
-  SimpleTaskInput(this.target, this.result, {this.flushOnAccess: false});
-
-  /**
-   * Initialize a newly created task input that computes the input by accessing
-   * the given [result] associated with the given [target].
-   */
-  SimpleTaskInput._unflushable(this.target, this.result)
-      : flushOnAccess = false;
-
-  @override
-  TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [SimpleTaskInput].
- */
-class SimpleTaskInputBuilder<V> implements TaskInputBuilder<V> {
-  /**
-   * The state value indicating that the builder is positioned before the single
-   * result.
-   */
-  static const _BEFORE = -1;
-
-  /**
-   * The state value indicating that the builder is positioned at the single
-   * result.
-   */
-  static const _AT = 0;
-
-  /**
-   * The state value indicating that the builder is positioned after the single
-   * result.
-   */
-  static const _AFTER = 1;
-
-  /**
-   * The input being built.
-   */
-  final SimpleTaskInput<V> input;
-
-  /**
-   * The value of the input being built.  `null` if the value hasn't been set
-   * yet, or if no result is available ([currentValueNotAvailable] was called).
-   */
-  V _resultValue = null;
-
-  /**
-   * The state of the builder.
-   */
-  int _state = _BEFORE;
-
-  /**
-   * A flag indicating whether the result value was explicitly set.
-   */
-  bool _resultSet = false;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  SimpleTaskInputBuilder(this.input);
-
-  @override
-  ResultDescriptor get currentResult => _state == _AT ? input.result : null;
-
-  @override
-  AnalysisTarget get currentTarget => _state == _AT ? input.target : null;
-
-  @override
-  void set currentValue(Object value) {
-    if (_state != _AT) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    if (value is! V) {
-      throw new StateError(
-          'Cannot build $input: computed ${value.runtimeType}, needed $V');
-    }
-    _resultValue = value as V;
-    _resultSet = true;
-  }
-
-  @override
-  bool get flushOnAccess => input.flushOnAccess;
-
-  @override
-  V get inputValue {
-    if (_state != _AFTER) {
-      throw new StateError('Result value has not been created');
-    }
-    return _resultValue;
-  }
-
-  @override
-  void currentValueNotAvailable() {
-    if (_state != _AT) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    _resultValue = null;
-    _resultSet = true;
-  }
-
-  @override
-  bool moveNext() {
-    if (_state == _BEFORE) {
-      _state = _AT;
-      return true;
-    } else {
-      if (!_resultSet) {
-        throw new StateError(
-            'The value of the current result must be set before moving to the next result.');
-      }
-      _state = _AFTER;
-      return false;
-    }
-  }
-}
-
-abstract class TaskInputImpl<V> implements TaskInput<V> {
-  @override
-  ListTaskInput<E> mappedToList<E>(List<E> mapper(V value)) {
-    return new ObjectToListTaskInput(
-        this, (Object element) => mapper(element as V));
-  }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on one or more other task
- * inputs. The task inputs to be built are specified by a table mapping the name
- * of the input to the task used to access the input's value.
- */
-class TopLevelTaskInputBuilder
-    implements TaskInputBuilder<Map<String, Object>> {
-  /**
-   * The descriptors describing the inputs to be built.
-   */
-  final Map<String, TaskInput> inputDescriptors;
-
-  /**
-   * The names of the inputs. There are the keys from the [inputDescriptors] in
-   * an indexable form.
-   */
-  List<String> inputNames;
-
-  /**
-   * The index of the input name associated with the current result and target.
-   */
-  int nameIndex = -1;
-
-  /**
-   * The builder used to build the current result.
-   */
-  TaskInputBuilder currentBuilder;
-
-  /**
-   * The inputs that are being or have been built. The map will be incomplete
-   * unless the method [moveNext] returns `false`.
-   */
-  final Map<String, Object> inputs = new HashMap<String, Object>();
-
-  /**
-   * Initialize a newly created task input builder to build the inputs described
-   * by the given [inputDescriptors].
-   */
-  TopLevelTaskInputBuilder(this.inputDescriptors) {
-    inputNames = inputDescriptors.keys.toList();
-  }
-
-  @override
-  ResultDescriptor get currentResult {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentResult;
-  }
-
-  @override
-  AnalysisTarget get currentTarget {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentTarget;
-  }
-
-  @override
-  void set currentValue(Object value) {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValue = value;
-  }
-
-  @override
-  bool get flushOnAccess => currentBuilder.flushOnAccess;
-
-  @override
-  Map<String, Object> get inputValue {
-    if (nameIndex < inputNames.length) {
-      throw new StateError('Result value has not been created');
-    }
-    return inputs;
-  }
-
-  /**
-   * Assuming that there is a current input, return its name.
-   */
-  String get _currentName => inputNames[nameIndex];
-
-  @override
-  void currentValueNotAvailable() {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValueNotAvailable();
-  }
-
-  @override
-  bool moveNext() {
-    if (nameIndex >= inputNames.length) {
-      // We have already computed all of the results, so just return false.
-      return false;
-    }
-    if (nameIndex < 0) {
-      // This is the first time moveNext has been invoked, so we just determine
-      // whether there are any results to be computed.
-      nameIndex = 0;
-    } else {
-      if (currentBuilder.moveNext()) {
-        // We are still working on building the value associated with the
-        // current name.
-        return true;
-      }
-      if (currentBuilder.inputValue != null) {
-        inputs[_currentName] = currentBuilder.inputValue;
-      }
-      nameIndex++;
-    }
-    if (nameIndex >= inputNames.length) {
-      // There is no next value, so we're done.
-      return false;
-    }
-    currentBuilder = inputDescriptors[_currentName].createBuilder();
-    while (!currentBuilder.moveNext()) {
-      if (currentBuilder.inputValue != null) {
-        inputs[_currentName] = currentBuilder.inputValue;
-      }
-      nameIndex++;
-      if (nameIndex >= inputNames.length) {
-        // There is no next value, so we're done.
-        return false;
-      }
-      currentBuilder = inputDescriptors[_currentName].createBuilder();
-    }
-    return true;
-  }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and a collection of the analysis results is used as the input to the task.
- */
-abstract class _ListToCollectionTaskInput<B, E, C> extends TaskInputImpl<C> {
-  /**
-   * The accessor used to access the list of elements being mapped.
-   */
-  final TaskInput<List<B>> baseAccessor;
-
-  /**
-   * The function used to convert an element in the list returned by the
-   * [baseAccessor] to a task input.
-   */
-  final GenerateTaskInputs<B, E> generateTaskInputs;
-
-  /**
-   * Initialize a result accessor to use the given [baseAccessor] to access a
-   * list of values that can be passed to the given [generateTaskInputs] to
-   * generate a list of task inputs that can be used to access the elements of
-   * the input being accessed.
-   */
-  _ListToCollectionTaskInput(this.baseAccessor, this.generateTaskInputs);
-}
-
-/**
- * A [TaskInputBuilder] used to build an [_ListToCollectionTaskInput].
- */
-abstract class _ListToCollectionTaskInputBuilder<B, E, C>
-    implements TaskInputBuilder<C> {
-  /**
-   * The input being built.
-   */
-  final _ListToCollectionTaskInput<B, E, C> input;
-
-  /**
-   * The builder used to build the current result.
-   */
-  TaskInputBuilder currentBuilder;
-
-  /**
-   * The list of values computed by the [input]'s base accessor.
-   */
-  List<B> _baseList = null;
-
-  /**
-   * The index in the [_baseList] of the value for which a value is currently
-   * being built.
-   */
-  int _baseListIndex = -1;
-
-  /**
-   * The element of the [_baseList] for which a value is currently being built.
-   */
-  B _baseListElement;
-
-  /**
-   * Initialize a newly created task input builder that computes the result
-   * specified by the given [input].
-   */
-  _ListToCollectionTaskInputBuilder(this.input);
-
-  @override
-  ResultDescriptor get currentResult {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentResult;
-  }
-
-  @override
-  AnalysisTarget get currentTarget {
-    if (currentBuilder == null) {
-      return null;
-    }
-    return currentBuilder.currentTarget;
-  }
-
-  @override
-  void set currentValue(Object value) {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValue = value;
-  }
-
-  @override
-  bool get flushOnAccess => currentBuilder.flushOnAccess;
-
-  @override
-  C get inputValue {
-    if (currentBuilder != null || _resultValue == null) {
-      throw new StateError('Result value has not been created');
-    }
-    return _resultValue;
-  }
-
-  /**
-   * The list of values being built.
-   */
-  C get _resultValue;
-
-  @override
-  void currentValueNotAvailable() {
-    if (currentBuilder == null) {
-      throw new StateError(
-          'Cannot set the result value when there is no current result');
-    }
-    currentBuilder.currentValueNotAvailable();
-  }
-
-  @override
-  bool moveNext() {
-    if (currentBuilder == null) {
-      if (_resultValue == null) {
-        // This is the first time moveNext has been invoked, so start by
-        // computing the list of values from which the results will be derived.
-        currentBuilder = input.baseAccessor.createBuilder();
-        return currentBuilder.moveNext();
-      } else {
-        // We have already computed all of the results, so just return false.
-        return false;
-      }
-    }
-    if (currentBuilder.moveNext()) {
-      return true;
-    }
-    if (_resultValue == null) {
-      // We have finished computing the list of values from which the results
-      // will be derived.
-      _baseList = currentBuilder.inputValue as List<B>;
-      if (_baseList == null) {
-        // No base list could be computed due to a circular dependency.  Use an
-        // empty list so that no further results will be computed.
-        _baseList = [];
-      }
-      _baseListIndex = 0;
-      _initResultValue();
-    } else {
-      // We have finished computing one of the elements in the result list.
-      if (currentBuilder.inputValue != null) {
-        _addResultElement(_baseListElement, currentBuilder.inputValue as E);
-      }
-      _baseListIndex++;
-    }
-    if (_baseListIndex >= _baseList.length) {
-      currentBuilder = null;
-      return false;
-    }
-    _baseListElement = _baseList[_baseListIndex];
-    currentBuilder = input.generateTaskInputs(_baseListElement).createBuilder();
-    return currentBuilder.moveNext();
-  }
-
-  void _addResultElement(B baseElement, E resultElement);
-  void _initResultValue();
-}
diff --git a/pkg/analyzer/lib/src/task/manager.dart b/pkg/analyzer/lib/src/task/manager.dart
deleted file mode 100644
index 009afaf..0000000
--- a/pkg/analyzer/lib/src/task/manager.dart
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * An object that manages the information about the tasks that have been
- * defined.
- */
-class TaskManager {
-  /**
-   * A table mapping [ResultDescriptor]s to a list of [TaskDescriptor]s
-   * for the tasks that can be used to compute the result.
-   */
-  Map<ResultDescriptor, List<TaskDescriptor>> taskMap =
-      new HashMap<ResultDescriptor, List<TaskDescriptor>>();
-
-  /**
-   * A list of the results that are to be computed for all sources within an
-   * analysis root.
-   */
-  Set<ResultDescriptor> generalResults = new Set<ResultDescriptor>();
-
-  /**
-   * A list of the results that are to be computed for priority sources.
-   */
-  Set<ResultDescriptor> priorityResults = new Set<ResultDescriptor>();
-
-  /**
-   * Add the given [result] to the list of results that are to be computed for
-   * all sources within an analysis root.
-   */
-  void addGeneralResult(ResultDescriptor result) {
-    generalResults.add(result);
-  }
-
-  /**
-   * Add the given [result] to the list of results that are to be computed for
-   * priority sources.
-   */
-  void addPriorityResult(ResultDescriptor result) {
-    priorityResults.add(result);
-  }
-
-  /**
-   * Add the given [descriptor] to the list of analysis task descriptors that
-   * can be used to compute analysis results.
-   */
-  void addTaskDescriptor(TaskDescriptor descriptor) {
-    descriptor.results.forEach((ResultDescriptor result) {
-      //
-      // Add the result to the task map.
-      //
-      List<TaskDescriptor> descriptors = taskMap[result];
-      if (descriptors == null) {
-        descriptors = <TaskDescriptor>[];
-        taskMap[result] = descriptors;
-      }
-      descriptors.add(descriptor);
-    });
-  }
-
-  /**
-   * Add the task descriptors in the given list of [descriptors] to the list of
-   * analysis task descriptors that can be used to compute analysis results.
-   */
-  void addTaskDescriptors(List<TaskDescriptor> descriptors) {
-    descriptors.forEach(addTaskDescriptor);
-  }
-
-  /**
-   * Find a task that will compute the given [result] for the given [target].
-   */
-  TaskDescriptor findTask(AnalysisTarget target, ResultDescriptor result) {
-    List<TaskDescriptor> descriptors = taskMap[result];
-    if (descriptors == null) {
-      throw new AnalysisException(
-          'No tasks registered to compute $result for $target');
-    }
-    return _findBestTask(descriptors, target);
-  }
-
-  /**
-   * Remove the given [result] from the list of results that are to be computed
-   * for all sources within an analysis root.
-   */
-  void removeGeneralResult(ResultDescriptor result) {
-    generalResults.remove(result);
-  }
-
-  /**
-   * Remove the given [result] from the list of results that are to be computed
-   * for priority sources.
-   */
-  void removePriorityResult(ResultDescriptor result) {
-    priorityResults.remove(result);
-  }
-
-  /**
-   * Given a list of task [descriptors] that can be used to compute some
-   * unspecified result for the given [target], return the descriptor that
-   * should be used to compute the result.
-   */
-  TaskDescriptor _findBestTask(
-      List<TaskDescriptor> descriptors, AnalysisTarget target) {
-    TaskDescriptor best = null;
-    for (TaskDescriptor descriptor in descriptors) {
-      TaskSuitability suitability = descriptor.suitabilityFor(target);
-      if (suitability == TaskSuitability.HIGHEST) {
-        return descriptor;
-      } else if (best == null && suitability == TaskSuitability.LOWEST) {
-        best = descriptor;
-      }
-    }
-    return best;
-  }
-}
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
deleted file mode 100644
index ec62312..0000000
--- a/pkg/analyzer/lib/src/task/model.dart
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/inputs.dart';
-
-/**
- * The default [ResultCachingPolicy], results are never flushed.
- */
-const ResultCachingPolicy DEFAULT_CACHING_POLICY =
-    const SimpleResultCachingPolicy(-1, -1);
-
-/**
- * A concrete implementation of a [ListResultDescriptor].
- */
-class ListResultDescriptorImpl<E> extends ResultDescriptorImpl<List<E>>
-    implements ListResultDescriptor<E> {
-  /**
-   * Initialize a newly created analysis result to have the given [name] and
-   * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
-   * values associated with this result will remain in the cache.
-   */
-  ListResultDescriptorImpl(String name, List<E> defaultValue,
-      {ResultCachingPolicy cachingPolicy: DEFAULT_CACHING_POLICY})
-      : super(name, defaultValue, cachingPolicy: cachingPolicy);
-
-  @override
-  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}) {
-    if (flushOnAccess) {
-      throw new StateError('Cannot flush a list of values');
-    }
-    return new ListTaskInputImpl<E>(target, this);
-  }
-}
-
-/**
- * A concrete implementation of a [ResultDescriptor].
- */
-class ResultDescriptorImpl<V> implements ResultDescriptor<V> {
-  static int _NEXT_HASH = 0;
-
-  @override
-  final hashCode = _NEXT_HASH++;
-
-  /**
-   * The name of the result, used for debugging.
-   */
-  final String name;
-
-  /**
-   * Return the default value for results described by this descriptor.
-   */
-  final V defaultValue;
-
-  /**
-   * The caching policy for results described by this descriptor.
-   */
-  final ResultCachingPolicy cachingPolicy;
-
-  /**
-   * Initialize a newly created analysis result to have the given [name] and
-   * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
-   * values associated with this result will remain in the cache.
-   */
-  ResultDescriptorImpl(this.name, this.defaultValue,
-      {this.cachingPolicy: DEFAULT_CACHING_POLICY});
-
-  @override
-  bool operator ==(Object other) {
-    return other is ResultDescriptorImpl && other.hashCode == hashCode;
-  }
-
-  @override
-  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}) =>
-      new SimpleTaskInput<V>(target, this, flushOnAccess: flushOnAccess);
-
-  @override
-  String toString() => name;
-}
-
-/**
- * A simple [ResultCachingPolicy] implementation that consider all the objects
- * to be of the size `1`.
- */
-class SimpleResultCachingPolicy implements ResultCachingPolicy {
-  @override
-  final int maxActiveSize;
-
-  @override
-  final int maxIdleSize;
-
-  const SimpleResultCachingPolicy(this.maxActiveSize, this.maxIdleSize);
-
-  @override
-  int measure(Object object) => 1;
-}
-
-/**
- * A concrete implementation of a [TaskDescriptor].
- */
-class TaskDescriptorImpl implements TaskDescriptor {
-  /**
-   * The name of the described task, used for debugging.
-   */
-  final String name;
-
-  /**
-   * The function used to build the analysis task.
-   */
-  final BuildTask buildTask;
-
-  /**
-   * The function used to build the inputs to the task.
-   */
-  @override
-  final CreateTaskInputs createTaskInputs;
-
-  /**
-   * A list of the analysis results that will be computed by the described task.
-   */
-  @override
-  final List<ResultDescriptor> results;
-
-  /**
-   * The function used to determine whether the described task is suitable for
-   * a given target.
-   */
-  final SuitabilityFor _suitabilityFor;
-
-  /**
-   * Initialize a newly created task descriptor to have the given [name] and to
-   * describe a task that takes the inputs built using the given [inputBuilder],
-   * and produces the given [results]. The [buildTask] function will be used to
-   * create the instance of [AnalysisTask] being described. If provided, the
-   * [isAppropriateFor] function will be used to determine whether the task can
-   * be used on a specific target.
-   */
-  TaskDescriptorImpl(
-      this.name, this.buildTask, this.createTaskInputs, this.results,
-      {SuitabilityFor suitabilityFor})
-      : _suitabilityFor = suitabilityFor ?? _defaultSuitability;
-
-  @override
-  AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
-      Map<String, dynamic> inputs) {
-    AnalysisTask task = buildTask(context, target);
-    task.inputs = inputs;
-    return task;
-  }
-
-  @override
-  TaskSuitability suitabilityFor(AnalysisTarget target) =>
-      _suitabilityFor(target);
-
-  @override
-  String toString() => name;
-
-  /**
-   * The function that will be used to determine the suitability of a task if no
-   * other function is provided.
-   */
-  static TaskSuitability _defaultSuitability(AnalysisTarget target) =>
-      TaskSuitability.LOWEST;
-}
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index bd86f884..634baf4 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -8,7 +8,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart' show TokenType;
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -582,7 +581,7 @@
   @override
   void visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
-    var type = resolutionMap.staticElementForConstructorReference(node)?.type;
+    var type = node.staticElement?.type;
     // TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation
     // in the element_resolver to handle the case that the element is null
     // and emit an error.  In the meantime, just be defensive here.
@@ -657,7 +656,7 @@
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
     var element = node.staticElement;
     if (element != null) {
-      var type = resolutionMap.staticElementForConstructorReference(node).type;
+      var type = node.staticElement.type;
       checkArgumentList(node.argumentList, type);
     }
     node.visitChildren(this);
@@ -674,9 +673,8 @@
 
   @override
   Object visitVariableDeclaration(VariableDeclaration node) {
-    VariableElement variableElement = node == null
-        ? null
-        : resolutionMap.elementDeclaredByVariableDeclaration(node);
+    VariableElement variableElement =
+        node == null ? null : node.declaredElement;
     AstNode parent = node.parent;
     if (variableElement != null &&
         parent is VariableDeclarationList &&
@@ -720,7 +718,7 @@
   void _checkCompoundAssignment(AssignmentExpression expr) {
     var op = expr.operator.type;
     assert(op.isAssignmentOperator && op != TokenType.EQ);
-    var methodElement = resolutionMap.staticElementForMethodReference(expr);
+    var methodElement = expr.staticElement;
     if (methodElement == null) {
       // Dynamic invocation.
       _recordDynamicInvoke(expr, expr.leftHandSide);
@@ -1290,9 +1288,7 @@
           ? node.firstTokenAfterCommentAndMetadata.offset
           : node.offset;
       int length = node.end - begin;
-      var source = resolutionMap
-          .elementDeclaredByCompilationUnit(node.root as CompilationUnit)
-          .source;
+      var source = (node.root as CompilationUnit).declaredElement.source;
       var error =
           new AnalysisError(source, begin, length, errorCode, arguments);
       reporter.onError(error);
@@ -1396,8 +1392,7 @@
   _OverrideChecker(CodeChecker checker) : rules = checker.rules;
 
   void check(Declaration node) {
-    var element =
-        resolutionMap.elementDeclaredByDeclaration(node) as ClassElement;
+    var element = node.declaredElement as ClassElement;
     if (element.type.isObject) {
       return;
     }
diff --git a/pkg/analyzer/lib/src/task/yaml.dart b/pkg/analyzer/lib/src/task/yaml.dart
deleted file mode 100644
index 56ea51c..0000000
--- a/pkg/analyzer/lib/src/task/yaml.dart
+++ /dev/null
@@ -1,153 +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.
-
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/api/yaml.dart';
-import 'package:analyzer/src/task/general.dart';
-import 'package:source_span/source_span.dart';
-import 'package:yaml/yaml.dart';
-
-/**
- * A task that scans the content of a YAML file, producing a YAML document.
- */
-class ParseYamlTask extends SourceBasedAnalysisTask {
-  /**
-   * The name of the input whose value is the content of the file.
-   */
-  static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
-
-  /**
-   * The task descriptor describing this kind of task.
-   */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ParseYamlTask',
-      createTask,
-      buildInputs,
-      <ResultDescriptor>[YAML_DOCUMENT, YAML_ERRORS, LINE_INFO],
-      suitabilityFor: suitabilityFor);
-
-  /**
-   * Initialize a newly created task to access the content of the source
-   * associated with the given [target] in the given [context].
-   */
-  ParseYamlTask(InternalAnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  void internalPerform() {
-    Source source = target.source;
-    String uri = source.uri.toString();
-    String content = getRequiredInput(CONTENT_INPUT_NAME);
-
-    if (context.getModificationStamp(source) < 0) {
-      String message = 'Content could not be read';
-      if (context is InternalAnalysisContext) {
-        CacheEntry entry =
-            (context as InternalAnalysisContext).getCacheEntry(target);
-        CaughtException exception = entry.exception;
-        if (exception != null) {
-          message = exception.toString();
-        }
-      }
-      //
-      // Record outputs.
-      //
-      outputs[YAML_DOCUMENT] = loadYamlDocument('', sourceUrl: uri);
-      outputs[YAML_ERRORS] = <AnalysisError>[
-        new AnalysisError(
-            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])
-      ];
-      outputs[LINE_INFO] = new LineInfo(<int>[0]);
-    } else {
-      YamlDocument document;
-      List<AnalysisError> errors = <AnalysisError>[];
-      try {
-        document = loadYamlDocument(content, sourceUrl: uri);
-      } on YamlException catch (exception) {
-        SourceSpan span = exception.span;
-        int offset = span.start.offset;
-        int length = span.end.offset - offset;
-        errors.add(new AnalysisError(source, offset, length,
-            YamlErrorCode.PARSE_ERROR, [exception.message]));
-      } catch (exception, stackTrace) {
-        throw new AnalysisException('Error while parsing ${source.fullName}',
-            new CaughtException(exception, stackTrace));
-      }
-      //
-      // Record outputs.
-      //
-      outputs[YAML_DOCUMENT] = document;
-      outputs[YAML_ERRORS] = errors;
-      outputs[LINE_INFO] = new LineInfo.fromContent(content);
-    }
-  }
-
-  /**
-   * Return a map from the names of the inputs of this kind of task to the task
-   * input descriptors describing those inputs for a task with the given
-   * [source].
-   */
-  static Map<String, TaskInput> buildInputs(AnalysisTarget source) {
-    return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};
-  }
-
-  /**
-   * Create a [ParseYamlTask] based on the given [target] in the given [context].
-   */
-  static ParseYamlTask createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new ParseYamlTask(context, target);
-  }
-
-  /**
-   * Return an indication of how suitable this task is for the given [target].
-   */
-  static TaskSuitability suitabilityFor(AnalysisTarget target) {
-    if (target is Source && target.shortName.endsWith('.yaml')) {
-      return TaskSuitability.HIGHEST;
-    }
-    return TaskSuitability.NONE;
-  }
-}
-
-/**
- * The error codes used for errors in YAML files.
- */
-class YamlErrorCode extends ErrorCode {
-  // TODO(brianwilkerson) Move this class to error.dart.
-
-  /**
-   * An error code indicating that there is a syntactic error in the file.
-   *
-   * Parameters:
-   * 0: the error message from the parse error
-   */
-  static const YamlErrorCode PARSE_ERROR =
-      const YamlErrorCode('PARSE_ERROR', '{0}');
-
-  /**
-   * Initialize a newly created error code to have the given [name]. The message
-   * associated with the error will be created from the given [message]
-   * template. The correction associated with the error will be created from the
-   * given [correction] template.
-   */
-  const YamlErrorCode(String name, String message, {String correction})
-      : super.temporary(name, message, correction: correction);
-
-  @override
-  ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
-
-  @override
-  ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
-}
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index ed79e1a..382edb0 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -34,7 +34,7 @@
 
   Future<R> then<R>(FutureOr<R> onValue(T value)) => null;
   Future<T> whenComplete(action());
-  
+
   static Future<List<T>> wait<T>(Iterable<Future<T>> futures) => null;
 }
 
@@ -43,10 +43,12 @@
 abstract class Completer<T> {
   factory Completer() => null;
   factory Completer.sync() => null;
+
   Future<T> get future;
+  bool get isCompleted;
+
   void complete([value]);
   void completeError(Object error, [StackTrace stackTrace]);
-  bool get isCompleted;
 }
 
 abstract class Timer {
@@ -59,27 +61,31 @@
     '$sdkRoot/lib/async/stream.dart',
     r'''
 part of dart.async;
+
 abstract class Stream<T> {
+  Stream();
+  factory Stream.fromIterable(Iterable<T> data) => null;
+
   Future<T> get first;
+
   StreamSubscription<T> listen(void onData(T event),
                                { Function onError,
                                  void onDone(),
                                  bool cancelOnError});
-  Stream();
-  factory Stream.fromIterable(Iterable<T> data) => null;
 }
 
 abstract class StreamIterator<T> {}
 
 abstract class StreamSubscription<T> {
+  bool get isPaused;
+
+  Future<E> asFuture<E>([E futureValue]);
   Future cancel();
   void onData(void handleData(T data));
   void onError(Function handleError);
   void onDone(void handleDone());
   void pause([Future resumeSignal]);
   void resume();
-  bool get isPaused;
-  Future<E> asFuture<E>([E futureValue]);
 }
 
 abstract class StreamTransformer<S, T> {}
@@ -106,15 +112,59 @@
     '''
 library dart.collection;
 
-abstract class HashMap<K, V> implements Map<K, V> {}
-abstract class LinkedHashMap<K, V> implements Map<K, V> {
-  factory LinkedHashMap(
+abstract class HashMap<K, V> implements Map<K, V> {
+  external factory HashMap(
       {bool equals(K key1, K key2),
       int hashCode(K key),
-      bool isValidKey(potentialKey)}) => null;
+      bool isValidKey(potentialKey)});
+
+  external factory HashMap.identity();
+
+  factory HashMap.from(Map other) => null;
+
+  factory HashMap.of(Map<K, V> other) => null;
+
+  factory HashMap.fromIterable(Iterable iterable,
+      {K key(element), V value(element)}) => null;
+
+  factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) => null;
+
+  factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) => null;
 }
-abstract class HashSet<E> implements Set<E> {}
-abstract class LinkedHashSet<E> implements Set<E> {}
+
+abstract class LinkedHashMap<K, V> implements Map<K, V> {
+  external factory LinkedHashMap(
+      {bool equals(K key1, K key2),
+      int hashCode(K key),
+      bool isValidKey(potentialKey)});
+
+  external factory LinkedHashMap.identity();
+
+  factory LinkedHashMap.from(Map other) => null;
+
+  factory LinkedHashMap.of(Map<K, V> other) => null;
+
+  factory LinkedHashMap.fromIterable(Iterable iterable,
+      {K key(element), V value(element)}) => null;
+
+  factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values)
+      => null;
+
+  factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) => null;
+}
+
+abstract class LinkedHashSet<E> implements Set<E> {
+  external factory LinkedHashSet(
+      {bool equals(E e1, E e2),
+      int hashCode(E e),
+      bool isValidKey(potentialKey)});
+
+  external factory LinkedHashSet.identity();
+
+  factory LinkedHashSet.from(Iterable elements) => null;
+
+  factory LinkedHashSet.of(Iterable<E> elements) => null;
+}
 ''',
   )
 ]);
@@ -130,6 +180,7 @@
 import 'dart:async';
 
 abstract class Converter<S, T> implements StreamTransformer {}
+
 class JsonDecoder extends Converter<String, Object> {}
 ''',
     )
@@ -161,6 +212,7 @@
 abstract class bool extends Object {
   external const factory bool.fromEnvironment(String name,
       {bool defaultValue: false});
+
   bool operator &(bool other);
   bool operator |(bool other);
   bool operator ^(bool other);
@@ -197,6 +249,8 @@
   double operator -(num other);
   double operator -();
   double operator /(num other);
+  int operator ~/(num other);
+
   double abs();
   int ceil();
   double ceilToDouble();
@@ -207,12 +261,18 @@
   double roundToDouble();
   int truncate();
   double truncateToDouble();
-  int operator ~/(num other);
+
   external static double parse(String source, [double onError(String source)]);
 }
 
 class Duration implements Comparable<Duration> {}
 
+class Error {
+  Error();
+  static String safeToString(Object object) => '';
+  external StackTrace get stackTrace;
+}
+
 class Exception {
   factory Exception([var message]) => null;
 }
@@ -230,14 +290,12 @@
   int operator <<(int shiftAmount);
   int operator >>(int shiftAmount);
   int operator ^(int other);
-  String toString();
-
   int operator |(int other);
-
   int operator ~();
 
-  int gcd(int other);
   int abs();
+  int gcd(int other);
+  String toString();
 
   external static int parse(String source,
       {int radix, int onError(String source)});
@@ -248,11 +306,16 @@
 abstract class Iterable<E> {
   E get first;
   bool get isEmpty;
+  bool get isNotEmpty;
   Iterator<E> get iterator;
   int get length;
 
+  bool contains(Object element);
+
   Iterable<T> expand<T>(Iterable<T> f(E element));
 
+  E firstWhere(bool test(E element), { E orElse()});
+
   R fold<R>(R initialValue, R combine(R previousValue, E element)) => null;
 
   void forEach(void f(E element));
@@ -282,19 +345,26 @@
   void add(E value) {}
   void addAll(Iterable<E> iterable) {}
   void clear() {}
+  int indexOf(Object element);
 
   noSuchMethod(Invocation invocation) => null;
 }
 
 class Map<K, V> {
   factory Map() => null;
+
   factory Map.fromIterable(Iterable iterable,
       {K key(element), V value(element)}) => null;
+
   Iterable<K> get keys => null;
+  bool get isEmpty;
+  bool get isNotEmpty;
   int get length => 0;
   Iterable<V> get values => null;
+
   V operator [](K key) => null;
   void operator []=(K key, V value) {}
+
   Map<RK, RV> cast<RK, RV>() => null;
   bool containsKey(Object key) => false;
 }
@@ -318,22 +388,26 @@
   bool operator >=(num other);
   int operator >>(int other);
   int operator ^(int other);
+  int operator |(int other);
+  int operator ~();
+  int operator ~/(num other);
+
   num abs();
   int round();
   double toDouble();
   int toInt();
-  int operator |(int other);
-  int operator ~();
-  int operator ~/(num other);
 }
 
 class Object {
   const Object();
+
   int get hashCode => 0;
   Type get runtimeType => null;
+
   bool operator ==(other) => identical(this, other);
-  dynamic noSuchMethod(Invocation invocation) => null;
+
   String toString() => 'a string';
+  dynamic noSuchMethod(Invocation invocation) => null;
 }
 
 abstract class Pattern {}
@@ -347,6 +421,7 @@
   factory Set.identity() => null;
   factory Set.from(Iterable elements) => null;
   factory Set.of(Iterable<E> elements) => null;
+
   Set<R> cast<R>();
 }
 
@@ -355,14 +430,18 @@
 abstract class String implements Comparable<String>, Pattern {
   external factory String.fromCharCodes(Iterable<int> charCodes,
       [int start = 0, int end]);
+
   List<int> get codeUnits;
   int indexOf(Pattern pattern, [int start]);
   bool get isEmpty => false;
   bool get isNotEmpty => false;
   int get length => 0;
+
   String operator +(String other) => null;
   bool operator ==(Object other);
+
   int codeUnitAt(int index);
+  bool contains(String other, [int startIndex = 0]);
   String substring(int len) => null;
   String toLowerCase();
   String toUpperCase();
@@ -493,6 +572,57 @@
   ],
 );
 
+final MockSdkLibrary _LIB_IO = MockSdkLibrary(
+  [
+    MockSdkLibraryUnit(
+      'dart:io',
+      '$sdkRoot/lib/io/io.dart',
+      '''
+library dart.io;
+
+abstract class Directory implements FileSystemEntity {
+  factory Directory(String path) => null;
+
+  Future<bool> exists() async => true;
+  bool existsSync() => true;
+
+  Future<FileStat> stat() async => null;
+  FileStat statSync() => null;
+}
+
+abstract class File implements FileSystemEntity {
+  factory File(String path) => null;
+
+  Future<DateTime> lastModified();
+  DateTime lastModifiedSync();
+
+  Future<bool> exists() async => true;
+  bool existsSync() => true;
+
+  Future<FileStat> stat() async => null;
+  FileStat statSync() => null;
+}
+
+abstract class FileSystemEntity {
+  static Future<bool> isDirectory(String path) => true;
+  static bool isDirectorySync(String path) => true;
+
+  static Future<bool> isFile(String path) => true;
+  static bool isFileSync(String path) => true;
+
+  static Future<bool> isLink(String path) => true;
+  static bool isLinkSync(String path) => true;
+
+  static Future<FileSystemEntityType> type(
+    String path, {bool followLinks: true}) async => null;
+  static FileSystemEntityType typeSync(
+    String path, {bool followLinks: true}) => null;
+}
+''',
+    )
+  ],
+);
+
 final MockSdkLibrary _LIB_MATH = MockSdkLibrary(
   [
     MockSdkLibraryUnit(
@@ -512,11 +642,13 @@
 external double sin(num radians);
 external double sqrt(num radians);
 external double tan(num radians);
+
 class Random {
   bool nextBool() => true;
   double nextDouble() => 2.0;
   int nextInt() => 1;
 }
+
 class Point<T extends num> {}
 ''',
     )
@@ -530,6 +662,7 @@
   _LIB_COLLECTION,
   _LIB_CONVERT,
   _LIB_FOREIGN_HELPER,
+  _LIB_IO,
   _LIB_MATH,
   _LIB_HTML_DART2JS,
   _LIB_HTML_DARTIUM,
@@ -544,6 +677,7 @@
   'core': 'const LibraryInfo("core/core.dart")',
   'html': 'const LibraryInfo("html/dartium/html_dartium.dart", '
       'dart2jsPath: "html/dart2js/html_dart2js.dart")',
+  'io': 'const LibraryInfo("io/io.dart")',
   'math': 'const LibraryInfo("math/math.dart")',
   '_foreign_helper':
       'const LibraryInfo("_internal/js_runtime/lib/foreign_helper.dart")',
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart
new file mode 100644
index 0000000..856b19b
--- /dev/null
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart
@@ -0,0 +1,1070 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:meta/meta.dart';
+
+class MockSdkElements {
+  final LibraryElement coreLibrary;
+  final LibraryElement asyncLibrary;
+
+  factory MockSdkElements(
+    engine.AnalysisContext analysisContext,
+    NullabilitySuffix nullabilitySuffix,
+  ) {
+    var builder = _MockSdkElementsBuilder(analysisContext, nullabilitySuffix);
+    var coreLibrary = builder._buildCore();
+    var asyncLibrary = builder._buildAsync();
+    return MockSdkElements._(coreLibrary, asyncLibrary);
+  }
+
+  MockSdkElements._(this.coreLibrary, this.asyncLibrary);
+}
+
+class _MockSdkElementsBuilder {
+  final engine.AnalysisContext analysisContext;
+  final NullabilitySuffix nullabilitySuffix;
+
+  ClassElementImpl _boolElement;
+  ClassElementImpl _completerElement;
+  ClassElementImpl _deprecatedElement;
+  ClassElementImpl _doubleElement;
+  ClassElementImpl _functionElement;
+  ClassElementImpl _futureElement;
+  ClassElementImpl _futureOrElement;
+  ClassElementImpl _intElement;
+  ClassElementImpl _iterableElement;
+  ClassElementImpl _iteratorElement;
+  ClassElementImpl _listElement;
+  ClassElementImpl _mapElement;
+  ClassElementImpl _nullElement;
+  ClassElementImpl _numElement;
+  ClassElementImpl _objectElement;
+  ClassElementImpl _overrideElement;
+  ClassElementImpl _proxyElement;
+  ClassElementImpl _setElement;
+  ClassElementImpl _stackTraceElement;
+  ClassElementImpl _streamElement;
+  ClassElementImpl _streamSubscriptionElement;
+  ClassElementImpl _stringElement;
+  ClassElementImpl _symbolElement;
+  ClassElementImpl _typeElement;
+
+  InterfaceType _boolType;
+  InterfaceType _doubleType;
+  InterfaceType _intType;
+  InterfaceType _numType;
+  InterfaceType _objectType;
+  InterfaceType _stringType;
+  InterfaceType _typeType;
+
+  _MockSdkElementsBuilder(this.analysisContext, this.nullabilitySuffix);
+
+  ClassElementImpl get boolElement {
+    if (_boolElement != null) return _boolElement;
+
+    _boolElement = _class(name: 'bool');
+    _boolElement.supertype = objectType;
+
+    _boolElement.constructors = [
+      _constructor(
+        name: 'fromEnvironment',
+        isConst: true,
+        isFactory: true,
+        parameters: [
+          _requiredParameter('name', stringType),
+          _namedParameter('defaultValue', boolType),
+        ],
+      ),
+    ];
+
+    return _boolElement;
+  }
+
+  InterfaceType get boolType {
+    return _boolType ??= _interfaceType(boolElement);
+  }
+
+  ClassElementImpl get completerElement {
+    if (_completerElement != null) return _completerElement;
+
+    var tElement = _typeParameter('T');
+    _completerElement = _class(
+      name: 'Completer',
+      isAbstract: true,
+      typeParameters: [tElement],
+    );
+    _completerElement.supertype = objectType;
+
+    return _completerElement;
+  }
+
+  ClassElementImpl get deprecatedElement {
+    if (_deprecatedElement != null) return _deprecatedElement;
+
+    _deprecatedElement = _class(name: 'Deprecated');
+    _deprecatedElement.supertype = objectType;
+
+    _deprecatedElement.fields = <FieldElement>[
+      _field('message', stringType, isFinal: true),
+    ];
+
+    _deprecatedElement.accessors =
+        _deprecatedElement.fields.map((f) => f.getter).toList();
+
+    _deprecatedElement.constructors = [
+      _constructor(
+        isConst: true,
+        parameters: [
+          _requiredParameter('message', stringType),
+        ],
+      ),
+    ];
+
+    return _deprecatedElement;
+  }
+
+  ClassElementImpl get doubleElement {
+    if (_doubleElement != null) return _doubleElement;
+
+    _doubleElement = _class(name: 'double', isAbstract: true);
+    _doubleElement.supertype = numType;
+
+    FieldElement staticConstDoubleField(String name) {
+      return _field(name, doubleType, isStatic: true, isConst: true);
+    }
+
+    _doubleElement.fields = <FieldElement>[
+      staticConstDoubleField('nan'),
+      staticConstDoubleField('infinity'),
+      staticConstDoubleField('negativeInfinity'),
+      staticConstDoubleField('minPositive'),
+      staticConstDoubleField('maxFinite'),
+    ];
+
+    _doubleElement.accessors =
+        _doubleElement.fields.map((field) => field.getter).toList();
+
+    _doubleElement.methods = [
+      _method('+', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('*', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('-', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('%', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('/', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('~/', intType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('-', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('abs', doubleType),
+      _method('ceil', doubleType),
+      _method('floor', doubleType),
+      _method('remainder', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('round', doubleType),
+      _method('toString', stringType),
+      _method('truncate', doubleType),
+    ];
+
+    return _doubleElement;
+  }
+
+  InterfaceType get doubleType {
+    return _doubleType ??= _interfaceType(doubleElement);
+  }
+
+  DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
+
+  ClassElementImpl get functionElement {
+    if (_functionElement != null) return _functionElement;
+
+    _functionElement = _class(name: 'Function', isAbstract: true);
+    _functionElement.supertype = objectType;
+
+    return _functionElement;
+  }
+
+  InterfaceType get functionType {
+    return _interfaceType(functionElement);
+  }
+
+  ClassElementImpl get futureElement {
+    if (_futureElement != null) return _futureElement;
+
+    var tElement = _typeParameter('T');
+    var tType = _typeParameterType(tElement);
+
+    _futureElement = _class(
+      name: 'Future',
+      isAbstract: true,
+      typeParameters: [tElement],
+    );
+    _futureElement.supertype = objectType;
+
+    //   factory Future.value([FutureOr<T> value])
+    _futureElement.constructors = [
+      _constructor(
+        isFactory: true,
+        parameters: [
+          _positionalParameter('value', futureOrType(tType)),
+        ],
+      ),
+    ];
+
+    //   Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError})
+    var rElement = _typeParameter('R');
+    var rType = _typeParameterType(rElement);
+    _futureElement.methods = [
+      _method(
+        'then',
+        futureType(rType),
+        parameters: [
+          _requiredParameter(
+            'onValue',
+            _functionType(
+              returnType: futureOrType(rType),
+              parameters: [
+                _requiredParameter('value', tType),
+              ],
+            ),
+          ),
+          _positionalParameter('onError', functionType),
+        ],
+      ),
+    ];
+
+    return _futureElement;
+  }
+
+  ClassElementImpl get futureOrElement {
+    if (_futureOrElement != null) return _futureOrElement;
+
+    var tElement = _typeParameter('T');
+    _futureOrElement = _class(
+      name: 'FutureOr',
+      typeParameters: [tElement],
+    );
+    _futureOrElement.supertype = objectType;
+
+    return _futureOrElement;
+  }
+
+  ClassElementImpl get intElement {
+    if (_intElement != null) return _intElement;
+
+    _intElement = _class(name: 'int', isAbstract: true);
+    _intElement.supertype = numType;
+
+    _intElement.constructors = [
+      _constructor(
+        name: 'fromEnvironment',
+        isConst: true,
+        isFactory: true,
+        parameters: [
+          _requiredParameter('name', stringType),
+          _namedParameter('defaultValue', intType),
+        ],
+      ),
+    ];
+
+    _intElement.methods = [
+      _method('&', intType, parameters: [
+        _requiredParameter('other', intType),
+      ]),
+      _method('|', intType, parameters: [
+        _requiredParameter('other', intType),
+      ]),
+      _method('^', intType, parameters: [
+        _requiredParameter('other', intType),
+      ]),
+      _method('~', intType),
+      _method('<<', intType, parameters: [
+        _requiredParameter('shiftAmount', intType),
+      ]),
+      _method('>>', intType, parameters: [
+        _requiredParameter('shiftAmount', intType),
+      ]),
+      _method('-', intType),
+      _method('abs', intType),
+      _method('round', intType),
+      _method('floor', intType),
+      _method('ceil', intType),
+      _method('truncate', intType),
+      _method('toString', stringType),
+    ];
+
+    return _intElement;
+  }
+
+  InterfaceType get intType {
+    return _intType ??= _interfaceType(intElement);
+  }
+
+  ClassElementImpl get iterableElement {
+    if (_iterableElement != null) return _iterableElement;
+
+    var eElement = _typeParameter('E');
+    var eType = _typeParameterType(eElement);
+
+    _iterableElement = _class(
+      name: 'Iterable',
+      isAbstract: true,
+      typeParameters: [eElement],
+    );
+    _iterableElement.supertype = objectType;
+
+    _iterableElement.constructors = [
+      _constructor(isConst: true),
+    ];
+
+    _setAccessors(_iterableElement, [
+      _getter('iterator', iteratorType(eType)),
+      _getter('last', eType),
+    ]);
+
+    return _iterableElement;
+  }
+
+  ClassElementImpl get iteratorElement {
+    if (_iteratorElement != null) return _iteratorElement;
+
+    var eElement = _typeParameter('E');
+    var eType = _typeParameterType(eElement);
+
+    _iteratorElement = _class(
+      name: 'Iterator',
+      isAbstract: true,
+      typeParameters: [eElement],
+    );
+    _iteratorElement.supertype = objectType;
+
+    _setAccessors(_iterableElement, [
+      _getter('current', eType),
+    ]);
+
+    return _iteratorElement;
+  }
+
+  ClassElementImpl get listElement {
+    if (_listElement != null) return _listElement;
+
+    var eElement = _typeParameter('E');
+    var eType = _typeParameterType(eElement);
+
+    _listElement = _class(
+      name: 'List',
+      isAbstract: true,
+      typeParameters: [eElement],
+    );
+    _listElement.supertype = objectType;
+    _listElement.interfaces = [
+      iterableType(eType),
+    ];
+
+    _listElement.constructors = [
+      _constructor(isFactory: true, parameters: [
+        _positionalParameter('length', intType),
+      ]),
+    ];
+
+    _setAccessors(_listElement, [
+      _getter('length', intType),
+    ]);
+
+    _listElement.methods = [
+      _method('[]', eType, parameters: [
+        _requiredParameter('index', intType),
+      ]),
+      _method('[]=', voidType, parameters: [
+        _requiredParameter('index', intType),
+        _requiredParameter('value', eType),
+      ]),
+      _method('add', voidType, parameters: [
+        _requiredParameter('value', eType),
+      ]),
+    ];
+
+    return _listElement;
+  }
+
+  ClassElementImpl get mapElement {
+    if (_mapElement != null) return _mapElement;
+
+    var kElement = _typeParameter('K');
+    var vElement = _typeParameter('V');
+    var kType = _typeParameterType(kElement);
+    var vType = _typeParameterType(vElement);
+
+    _mapElement = _class(
+      name: 'Map',
+      isAbstract: true,
+      typeParameters: [kElement, vElement],
+    );
+    _mapElement.supertype = objectType;
+
+    _setAccessors(_mapElement, [
+      _getter('length', intType),
+    ]);
+
+    _mapElement.methods = [
+      _method('[]', vType, parameters: [
+        _requiredParameter('key', objectType),
+      ]),
+      _method('[]=', voidType, parameters: [
+        _requiredParameter('key', kType),
+        _requiredParameter('value', vType),
+      ]),
+    ];
+
+    return _mapElement;
+  }
+
+  ClassElementImpl get nullElement {
+    if (_nullElement != null) return _nullElement;
+
+    _nullElement = _class(name: 'Null');
+    _nullElement.supertype = objectType;
+
+    _nullElement.constructors = [
+      _constructor(
+        name: '_uninstantiatable',
+        isFactory: true,
+      ),
+    ];
+
+    return _nullElement;
+  }
+
+  ClassElementImpl get numElement {
+    if (_numElement != null) return _numElement;
+
+    _numElement = _class(name: 'num', isAbstract: true);
+    _numElement.supertype = objectType;
+
+    _numElement.methods = [
+      _method('+', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('-', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('*', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('%', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('/', doubleType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('~/', intType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('-', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('remainder', numType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('<', boolType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('<=', boolType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('>', boolType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('>=', boolType, parameters: [
+        _requiredParameter('other', numType),
+      ]),
+      _method('==', boolType, parameters: [
+        _requiredParameter('other', objectType),
+      ]),
+      _method('abs', numType),
+      _method('floor', numType),
+      _method('ceil', numType),
+      _method('round', numType),
+      _method('truncate', numType),
+      _method('toInt', intType),
+      _method('toDouble', doubleType),
+      _method('toStringAsFixed', stringType, parameters: [
+        _requiredParameter('fractionDigits', intType),
+      ]),
+      _method('toStringAsExponential', stringType, parameters: [
+        _requiredParameter('fractionDigits', intType),
+      ]),
+      _method('toStringAsPrecision', stringType, parameters: [
+        _requiredParameter('precision', intType),
+      ]),
+    ];
+
+    _setAccessors(_numElement, [
+      _getter('isInfinite', boolType),
+      _getter('isNaN', boolType),
+      _getter('isNegative', boolType),
+    ]);
+
+    return _numElement;
+  }
+
+  InterfaceType get numType {
+    return _numType ??= _interfaceType(numElement);
+  }
+
+  ClassElementImpl get objectElement {
+    if (_objectElement != null) return _objectElement;
+
+    _objectElement = ElementFactory.object;
+    _objectElement.interfaces = const <InterfaceType>[];
+    _objectElement.mixins = const <InterfaceType>[];
+    _objectElement.typeParameters = const <TypeParameterElement>[];
+    _objectElement.constructors = [
+      _constructor(isConst: true),
+    ];
+
+    _objectElement.methods = [
+      _method('toString', stringType),
+      _method('==', boolType, parameters: [
+        _requiredParameter('other', objectType),
+      ]),
+      _method('noSuchMethod', dynamicType, parameters: [
+        _requiredParameter('other', dynamicType),
+      ]),
+    ];
+
+    _setAccessors(_objectElement, [
+      _getter('hashCode', intType),
+      _getter('runtimeType', typeType),
+    ]);
+
+    return _objectElement;
+  }
+
+  InterfaceType get objectType {
+    return _objectType ??= _interfaceType(objectElement);
+  }
+
+  ClassElementImpl get overrideElement {
+    if (_overrideElement != null) return _overrideElement;
+
+    _overrideElement = _class(name: '_Override');
+    _overrideElement.supertype = objectType;
+
+    _overrideElement.constructors = [
+      _constructor(isConst: true),
+    ];
+
+    return _overrideElement;
+  }
+
+  ClassElementImpl get proxyElement {
+    if (_proxyElement != null) return _proxyElement;
+
+    _proxyElement = _class(name: '_Proxy');
+    _proxyElement.supertype = objectType;
+
+    _proxyElement.constructors = [
+      _constructor(isConst: true),
+    ];
+
+    return _proxyElement;
+  }
+
+  ClassElementImpl get setElement {
+    if (_setElement != null) return _setElement;
+
+    var eElement = _typeParameter('E');
+    var eType = _typeParameterType(eElement);
+
+    _setElement = _class(
+      name: 'Set',
+      isAbstract: true,
+      typeParameters: [eElement],
+    );
+    _setElement.supertype = objectType;
+    _setElement.interfaces = [
+      iterableType(eType),
+    ];
+
+    return _setElement;
+  }
+
+  ClassElementImpl get stackTraceElement {
+    if (_stackTraceElement != null) return _stackTraceElement;
+
+    _stackTraceElement = _class(name: 'StackTrace', isAbstract: true);
+    _stackTraceElement.supertype = objectType;
+
+    return _stackTraceElement;
+  }
+
+  ClassElementImpl get streamElement {
+    if (_streamElement != null) return _streamElement;
+
+    var tElement = _typeParameter('T');
+    var tType = _typeParameterType(tElement);
+
+    _streamElement = _class(
+      name: 'Stream',
+      isAbstract: true,
+      typeParameters: [tElement],
+    );
+    _streamElement.isAbstract = true;
+    _streamElement.supertype = objectType;
+
+    //    StreamSubscription<T> listen(void onData(T event),
+    //        {Function onError, void onDone(), bool cancelOnError});
+    _streamElement.methods = [
+      _method(
+        'listen',
+        streamSubscriptionType(tType),
+        parameters: [
+          _requiredParameter(
+            'onData',
+            _functionType(
+              returnType: voidType,
+              parameters: [
+                _requiredParameter('event', tType),
+              ],
+            ),
+          ),
+          _namedParameter('onError', functionType),
+          _namedParameter(
+            'onDone',
+            _functionType(returnType: voidType),
+          ),
+          _namedParameter('cancelOnError', boolType),
+        ],
+      ),
+    ];
+
+    return _streamElement;
+  }
+
+  ClassElementImpl get streamSubscriptionElement {
+    if (_streamSubscriptionElement != null) return _streamSubscriptionElement;
+
+    var tElement = _typeParameter('T');
+    _streamSubscriptionElement = _class(
+      name: 'StreamSubscription',
+      isAbstract: true,
+      typeParameters: [tElement],
+    );
+    _streamSubscriptionElement.supertype = objectType;
+
+    return _streamSubscriptionElement;
+  }
+
+  ClassElementImpl get stringElement {
+    if (_stringElement != null) return _stringElement;
+
+    _stringElement = _class(name: 'String', isAbstract: true);
+    _stringElement.supertype = objectType;
+
+    _stringElement.constructors = [
+      _constructor(
+        name: 'fromEnvironment',
+        isConst: true,
+        isFactory: true,
+        parameters: [
+          _requiredParameter('name', stringType),
+          _namedParameter('defaultValue', stringType),
+        ],
+      ),
+    ];
+
+    _setAccessors(_stringElement, [
+      _getter('isEmpty', boolType),
+      _getter('length', intType),
+      _getter('codeUnits', listType(intType)),
+    ]);
+
+    _stringElement.methods = [
+      _method('+', _stringType, parameters: [
+        _requiredParameter('other', _stringType),
+      ]),
+      _method('toLowerCase', _stringType),
+      _method('toUpperCase', _stringType),
+    ];
+
+    return _stringElement;
+  }
+
+  InterfaceType get stringType {
+    return _stringType ??= _interfaceType(stringElement);
+  }
+
+  ClassElementImpl get symbolElement {
+    if (_symbolElement != null) return _symbolElement;
+
+    _symbolElement = _class(name: 'Symbol', isAbstract: true);
+    _symbolElement.supertype = objectType;
+
+    _symbolElement.constructors = [
+      _constructor(
+        isConst: true,
+        isFactory: true,
+        parameters: [
+          _requiredParameter('name', stringType),
+        ],
+      ),
+    ];
+
+    return _symbolElement;
+  }
+
+  ClassElementImpl get typeElement {
+    if (_typeElement != null) return _typeElement;
+
+    _typeElement = _class(name: 'Type', isAbstract: true);
+    _typeElement.supertype = objectType;
+
+    return _typeElement;
+  }
+
+  InterfaceType get typeType {
+    return _typeType ??= _interfaceType(typeElement);
+  }
+
+  VoidTypeImpl get voidType => VoidTypeImpl.instance;
+
+  InterfaceType futureOrType(DartType elementType) {
+    return _interfaceType(
+      futureOrElement,
+      typeArguments: [elementType],
+    );
+  }
+
+  InterfaceType futureType(DartType elementType) {
+    return _interfaceType(
+      futureElement,
+      typeArguments: [elementType],
+    );
+  }
+
+  InterfaceType iterableType(DartType elementType) {
+    return _interfaceType(
+      iterableElement,
+      typeArguments: [elementType],
+    );
+  }
+
+  InterfaceType iteratorType(DartType elementType) {
+    return _interfaceType(
+      iteratorElement,
+      typeArguments: [elementType],
+    );
+  }
+
+  InterfaceType listType(DartType elementType) {
+    return _interfaceType(
+      listElement,
+      typeArguments: [elementType],
+    );
+  }
+
+  InterfaceType streamSubscriptionType(DartType valueType) {
+    return _interfaceType(
+      streamSubscriptionElement,
+      typeArguments: [valueType],
+    );
+  }
+
+  LibraryElementImpl _buildAsync() {
+    var asyncLibrary = LibraryElementImpl(
+      analysisContext,
+      null,
+      'dart.async',
+      0,
+      0,
+      nullabilitySuffix == NullabilitySuffix.none,
+    );
+
+    var asyncUnit = new CompilationUnitElementImpl();
+    var asyncSource = analysisContext.sourceFactory.forUri('dart:async');
+    asyncUnit.librarySource = asyncUnit.source = asyncSource;
+    asyncLibrary.definingCompilationUnit = asyncUnit;
+
+    asyncUnit.types = <ClassElement>[
+      completerElement,
+      futureElement,
+      futureOrElement,
+      streamElement,
+      streamSubscriptionElement
+    ];
+
+    return asyncLibrary;
+  }
+
+  LibraryElementImpl _buildCore() {
+    var coreUnit = CompilationUnitElementImpl();
+
+    var coreSource = analysisContext.sourceFactory.forUri('dart:core');
+    coreUnit.librarySource = coreUnit.source = coreSource;
+
+    coreUnit.types = <ClassElement>[
+      boolElement,
+      deprecatedElement,
+      doubleElement,
+      functionElement,
+      intElement,
+      iterableElement,
+      iteratorElement,
+      listElement,
+      mapElement,
+      nullElement,
+      numElement,
+      objectElement,
+      overrideElement,
+      proxyElement,
+      setElement,
+      stackTraceElement,
+      stringElement,
+      symbolElement,
+      typeElement,
+    ];
+
+    coreUnit.functions = <FunctionElement>[
+      _function('identical', boolType, parameters: [
+        _requiredParameter('a', objectType),
+        _requiredParameter('b', objectType),
+      ]),
+      _function('print', voidType, parameters: [
+        _requiredParameter('object', objectType),
+      ]),
+    ];
+
+    var deprecatedVariable = _topLevelVariable(
+      'deprecated',
+      _interfaceType(deprecatedElement),
+      isConst: true,
+    );
+
+    var overrideVariable = _topLevelVariable(
+      'override',
+      _interfaceType(overrideElement),
+      isConst: true,
+    );
+
+    var proxyVariable = _topLevelVariable(
+      'proxy',
+      _interfaceType(proxyElement),
+      isConst: true,
+    );
+
+    coreUnit.accessors = <PropertyAccessorElement>[
+      deprecatedVariable.getter,
+      overrideVariable.getter,
+      proxyVariable.getter,
+    ];
+    coreUnit.topLevelVariables = <TopLevelVariableElement>[
+      deprecatedVariable,
+      overrideVariable,
+      proxyVariable,
+    ];
+
+    var coreLibrary = LibraryElementImpl(
+      analysisContext,
+      null,
+      'dart.core',
+      0,
+      0,
+      nullabilitySuffix == NullabilitySuffix.none,
+    );
+    coreLibrary.definingCompilationUnit = coreUnit;
+
+    return coreLibrary;
+  }
+
+  ClassElementImpl _class({
+    @required String name,
+    bool isAbstract = false,
+    List<TypeParameterElement> typeParameters = const [],
+  }) {
+    var element = ClassElementImpl(name, 0);
+    element.typeParameters = typeParameters;
+    element.constructors = <ConstructorElement>[
+      _constructor(),
+    ];
+    return element;
+  }
+
+  ConstructorElement _constructor({
+    String name = '',
+    bool isConst = false,
+    bool isFactory = false,
+    List<ParameterElement> parameters = const [],
+  }) {
+    var element = ConstructorElementImpl(name, 0);
+    element.factory = isFactory;
+    element.isConst = isConst;
+    element.parameters = parameters;
+    return element;
+  }
+
+  FieldElement _field(
+    String name,
+    DartType type, {
+    bool isConst = false,
+    bool isFinal = false,
+    bool isStatic = false,
+  }) {
+    return ElementFactory.fieldElement(name, isStatic, isFinal, isConst, type);
+  }
+
+  FunctionElement _function(
+    String name,
+    DartType returnType, {
+    List<TypeParameterElement> typeFormals = const [],
+    List<ParameterElement> parameters = const [],
+  }) {
+    var element = FunctionElementImpl(name, 0)
+      ..parameters = parameters
+      ..returnType = returnType
+      ..typeParameters = typeFormals;
+    element.type = _typeOfExecutableElement(element);
+    return element;
+  }
+
+  FunctionType _functionType({
+    @required DartType returnType,
+    List<TypeParameterElement> typeFormals = const [],
+    List<ParameterElement> parameters = const [],
+  }) {
+    return FunctionTypeImpl.synthetic(returnType, typeFormals, parameters);
+  }
+
+  PropertyAccessorElement _getter(
+    String name,
+    DartType type, {
+    bool isStatic = false,
+  }) {
+    var field = FieldElementImpl(name, -1);
+    field.isFinal = true;
+    field.isStatic = isStatic;
+    field.isSynthetic = true;
+    field.type = type;
+
+    var getter = PropertyAccessorElementImpl(name, 0);
+    getter.getter = true;
+    getter.isStatic = isStatic;
+    getter.isSynthetic = false;
+    getter.returnType = type;
+    getter.type = _typeOfExecutableElement(getter);
+    getter.variable = field;
+
+    field.getter = getter;
+    return getter;
+  }
+
+  InterfaceType _interfaceType(
+    ClassElement element, {
+    List<DartType> typeArguments = const [],
+  }) {
+    return InterfaceTypeImpl.explicit(
+      element,
+      typeArguments,
+      nullabilitySuffix: nullabilitySuffix,
+    );
+  }
+
+  MethodElement _method(
+    String name,
+    DartType returnType, {
+    List<TypeParameterElement> typeFormals = const [],
+    List<ParameterElement> parameters = const [],
+  }) {
+    var element = MethodElementImpl(name, 0)
+      ..parameters = parameters
+      ..returnType = returnType
+      ..typeParameters = typeFormals;
+    element.type = _typeOfExecutableElement(element);
+    return element;
+  }
+
+  ParameterElement _namedParameter(String name, DartType type,
+      {String initializerCode}) {
+    var parameter = DefaultParameterElementImpl(name, 0);
+    parameter.parameterKind = ParameterKind.NAMED;
+    parameter.type = type;
+    parameter.defaultValueCode = initializerCode;
+    return parameter;
+  }
+
+  ParameterElement _positionalParameter(String name, DartType type) {
+    var parameter = ParameterElementImpl(name, 0);
+    parameter.parameterKind = ParameterKind.POSITIONAL;
+    parameter.type = type;
+    return parameter;
+  }
+
+  ParameterElement _requiredParameter(String name, DartType type) {
+    var parameter = ParameterElementImpl(name, 0);
+    parameter.parameterKind = ParameterKind.REQUIRED;
+    parameter.type = type;
+    return parameter;
+  }
+
+  /// Set the [accessors] and the corresponding fields for the [classElement].
+  void _setAccessors(
+    ClassElementImpl classElement,
+    List<PropertyAccessorElement> accessors,
+  ) {
+    classElement.accessors = accessors;
+    classElement.fields = accessors
+        .map((accessor) => accessor.variable)
+        .cast<FieldElement>()
+        .toList();
+  }
+
+  TopLevelVariableElement _topLevelVariable(
+    String name,
+    DartType type, {
+    bool isConst = false,
+    bool isFinal = false,
+  }) {
+    return ElementFactory.topLevelVariableElement3(
+        name, isConst, isFinal, type);
+  }
+
+  /// TODO(scheglov) We should do the opposite - build type in the element.
+  /// But build a similar synthetic / structured type.
+  FunctionType _typeOfExecutableElement(ExecutableElement element) {
+    return FunctionTypeImpl.synthetic(
+      element.returnType,
+      element.typeParameters,
+      element.parameters,
+    );
+  }
+
+  TypeParameterElementImpl _typeParameter(String name) {
+    return TypeParameterElementImpl(name, 0);
+  }
+
+  TypeParameterType _typeParameterType(TypeParameterElement element) {
+    return TypeParameterTypeImpl(
+      element,
+      nullabilitySuffix: nullabilitySuffix,
+    );
+  }
+}
diff --git a/pkg/analyzer/lib/src/util/sdk.dart b/pkg/analyzer/lib/src/util/sdk.dart
index abffd58..36ed5fd 100644
--- a/pkg/analyzer/lib/src/util/sdk.dart
+++ b/pkg/analyzer/lib/src/util/sdk.dart
@@ -19,7 +19,7 @@
 
   // The given SDK path does not work.
   // Then we're probably running on bots, in 'xcodebuild/ReleaseX64'.
-  // In this case 'vm_platform.dill' is next to the 'dart'.
+  // In this case 'vm_platform_strong.dill' is next to the 'dart'.
   return path.dirname(Platform.resolvedExecutable);
 }
 
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 72a8e45..5314552 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.38.2-dev
+version: 0.38.2
 author: Dart Team <misc@dartlang.org>
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -13,10 +13,10 @@
   collection: ^1.10.1
   convert: ^2.0.0
   crypto: '>=1.1.1 <3.0.0'
-  front_end: 0.1.23
+  front_end: 0.1.24
   glob: ^1.0.3
   html: '>=0.13.4+1 <0.15.0'
-  kernel: 0.3.23
+  kernel: 0.3.24
   meta: ^1.0.2
   package_config: '>=0.1.5 <2.0.0'
   path: '>=0.9.0 <2.0.0'
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index 585da6a..9c90698 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -30,6 +30,7 @@
     defineReflectiveTests(PreviousTokenTest);
     defineReflectiveTests(SimpleIdentifierTest);
     defineReflectiveTests(SimpleStringLiteralTest);
+    defineReflectiveTests(SpreadElementTest);
     defineReflectiveTests(StringInterpolationTest);
     defineReflectiveTests(VariableDeclarationTest);
   });
@@ -1189,6 +1190,21 @@
 }
 
 @reflectiveTest
+class SpreadElementTest extends ParserTestCase {
+  void test_notNullAwareSpread() {
+    final spread = AstTestFactory.spreadElement(
+        TokenType.PERIOD_PERIOD_PERIOD, AstTestFactory.nullLiteral());
+    expect(spread.isNullAware, isFalse);
+  }
+
+  void test_nullAwareSpread() {
+    final spread = AstTestFactory.spreadElement(
+        TokenType.PERIOD_PERIOD_PERIOD_QUESTION, AstTestFactory.nullLiteral());
+    expect(spread.isNullAware, isTrue);
+  }
+}
+
+@reflectiveTest
 class StringInterpolationTest extends ParserTestCase {
   void test_contentsOffsetEnd() {
     AstTestFactory.interpolationExpression(AstTestFactory.identifier3('bb'));
diff --git a/pkg/analyzer/test/generated/analysis_context_factory.dart b/pkg/analyzer/test/generated/analysis_context_factory.dart
deleted file mode 100644
index b7ae647..0000000
--- a/pkg/analyzer/test/generated/analysis_context_factory.dart
+++ /dev/null
@@ -1,543 +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.
-
-import 'dart:collection';
-
-import 'package:analyzer/dart/analysis/features.dart';
-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/type.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
-import 'package:analyzer/src/file_system/file_system.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/string_source.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
-import 'package:test/test.dart';
-
-/**
- * The class `AnalysisContextFactory` defines utility methods used to create analysis contexts
- * for testing purposes.
- */
-class AnalysisContextFactory {
-  static String _DART_MATH = "dart:math";
-
-  static String _DART_INTERCEPTORS = "dart:_interceptors";
-
-  static String _DART_JS_HELPER = "dart:_js_helper";
-
-  /**
-   * Create and return an analysis context that has a fake core library already
-   * resolved. The given [resourceProvider] will be used when accessing the file
-   * system.
-   */
-  static InternalAnalysisContext contextWithCore(
-      {UriResolver contributedResolver,
-      MemoryResourceProvider resourceProvider}) {
-    AnalysisContextForTests context = new AnalysisContextForTests();
-    return initContextWithCore(context, FeatureSet.forTesting(),
-        contributedResolver, resourceProvider);
-  }
-
-  /**
-   * Create and return an analysis context that uses the given [options] and has
-   * a fake core library already resolved. The given [resourceProvider] will be
-   * used when accessing the file system.
-   */
-  static InternalAnalysisContext contextWithCoreAndOptions(
-      AnalysisOptions options,
-      {MemoryResourceProvider resourceProvider}) {
-    AnalysisContextForTests context = new AnalysisContextForTests();
-    context._internalSetAnalysisOptions(options);
-    return initContextWithCore(
-        context, options.contextFeatures, null, resourceProvider);
-  }
-
-  /**
-   * Create and return an analysis context that has a fake core library already
-   * resolved. If not `null`, the given [packages] map will be used to create a
-   * package URI resolver. The given [resourceProvider] will be used when
-   * accessing the file system.
-   */
-  static InternalAnalysisContext contextWithCoreAndPackages(
-      Map<String, String> packages,
-      {MemoryResourceProvider resourceProvider}) {
-    AnalysisContextForTests context = new AnalysisContextForTests();
-    return initContextWithCore(context, FeatureSet.forTesting(),
-        new TestPackageUriResolver(packages), resourceProvider);
-  }
-
-  /**
-   * Initialize the given analysis [context] with a fake core library that has
-   * already been resolved. If not `null`, the given [contributedResolver] will
-   * be added to the context's source factory. The given [resourceProvider] will
-   * be used when accessing the file system.
-   */
-  static InternalAnalysisContext initContextWithCore(
-      InternalAnalysisContext context, FeatureSet featureSet,
-      [UriResolver contributedResolver,
-      MemoryResourceProvider resourceProvider]) {
-    DartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
-        resourceProvider, resourceProvider.convertPath('/fake/sdk'));
-    List<UriResolver> resolvers = <UriResolver>[
-      new DartUriResolver(sdk),
-      new ResourceUriResolver(resourceProvider)
-    ];
-    if (contributedResolver != null) {
-      resolvers.add(contributedResolver);
-    }
-    SourceFactory sourceFactory = new SourceFactory(resolvers);
-    context.sourceFactory = sourceFactory;
-    AnalysisContext coreContext = sdk.context;
-    //
-    // dart:core
-    //
-    TestTypeProvider provider = new TestTypeProvider();
-    CompilationUnitElementImpl coreUnit = new CompilationUnitElementImpl();
-    Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
-    coreUnit.librarySource = coreUnit.source = coreSource;
-    ClassElementImpl overrideClassElement =
-        ElementFactory.classElement2("_Override");
-    ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
-    proxyClassElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement(proxyClassElement, '', true)
-        ..isCycleFree = true
-        ..constantInitializers = <ConstructorInitializer>[]
-    ];
-    ClassElement objectClassElement = provider.objectType.element;
-    coreUnit.types = <ClassElement>[
-      provider.boolType.element,
-      provider.deprecatedType.element,
-      provider.doubleType.element,
-      provider.functionType.element,
-      provider.intType.element,
-      provider.iterableType.element,
-      provider.iteratorType.element,
-      provider.listType.element,
-      provider.mapType.element,
-      provider.nullType.element,
-      provider.numType.element,
-      objectClassElement,
-      overrideClassElement,
-      proxyClassElement,
-      provider.setType.element,
-      provider.stackTraceType.element,
-      provider.stringType.element,
-      provider.symbolType.element,
-      provider.typeType.element
-    ];
-    coreUnit.functions = <FunctionElement>[
-      ElementFactory.functionElement3("identical", provider.boolType,
-          <ClassElement>[objectClassElement, objectClassElement], null),
-      ElementFactory.functionElement3("print", VoidTypeImpl.instance,
-          <ClassElement>[objectClassElement], null)
-    ];
-    TopLevelVariableElement proxyTopLevelVariableElt =
-        ElementFactory.topLevelVariableElement3(
-            "proxy", true, false, proxyClassElement.type);
-    ConstTopLevelVariableElementImpl deprecatedTopLevelVariableElt =
-        ElementFactory.topLevelVariableElement3(
-            "deprecated", true, false, provider.deprecatedType);
-    TopLevelVariableElement overrideTopLevelVariableElt =
-        ElementFactory.topLevelVariableElement3(
-            "override", true, false, overrideClassElement.type);
-    {
-      ClassElement deprecatedElement = provider.deprecatedType.element;
-      InstanceCreationExpression initializer =
-          AstTestFactory.instanceCreationExpression2(
-              Keyword.CONST,
-              AstTestFactory.typeName(deprecatedElement),
-              [AstTestFactory.string2('next release')]);
-      ConstructorElement constructor = deprecatedElement.constructors.single;
-      initializer.staticElement = constructor;
-      initializer.constructorName.staticElement = constructor;
-      deprecatedTopLevelVariableElt.constantInitializer = initializer;
-    }
-    coreUnit.accessors = <PropertyAccessorElement>[
-      deprecatedTopLevelVariableElt.getter,
-      overrideTopLevelVariableElt.getter,
-      proxyTopLevelVariableElt.getter
-    ];
-    coreUnit.topLevelVariables = <TopLevelVariableElement>[
-      deprecatedTopLevelVariableElt,
-      overrideTopLevelVariableElt,
-      proxyTopLevelVariableElt
-    ];
-    LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
-        coreContext,
-        null,
-        AstTestFactory.libraryIdentifier2(["dart", "core"]),
-        featureSet.isEnabled(Feature.non_nullable));
-    coreLibrary.definingCompilationUnit = coreUnit;
-    //
-    // dart:async
-    //
-    LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
-        coreContext,
-        null,
-        AstTestFactory.libraryIdentifier2(["dart", "async"]),
-        featureSet.isEnabled(Feature.non_nullable));
-    CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
-    Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
-    asyncUnit.librarySource = asyncUnit.source = asyncSource;
-    asyncLibrary.definingCompilationUnit = asyncUnit;
-    // Future<T>
-    ClassElementImpl futureElement =
-        ElementFactory.classElement2("Future", ["T"]);
-    // FutureOr<T>
-    ClassElementImpl futureOrElement =
-        ElementFactory.classElement2("FutureOr", ["T"]);
-    futureElement.enclosingElement = asyncUnit;
-    //   factory Future.value([value])
-    ConstructorElementImpl futureConstructor =
-        ElementFactory.constructorElement2(futureElement, "value");
-    futureConstructor.parameters = <ParameterElement>[
-      ElementFactory.positionalParameter2("value", provider.dynamicType)
-    ];
-    futureConstructor.factory = true;
-    futureElement.constructors = <ConstructorElement>[futureConstructor];
-    //   Future<R> then<R>(FutureOr<R> onValue(T value), { Function onError });
-    TypeDefiningElement futureThenR = DynamicElementImpl.instance;
-    DartType onValueReturnType = DynamicTypeImpl.instance;
-    futureThenR = ElementFactory.typeParameterWithType('R');
-    onValueReturnType = futureOrElement.type.instantiate([futureThenR.type]);
-    FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
-        'onValue', onValueReturnType, [futureElement.typeParameters[0]], null);
-    thenOnValue.isSynthetic = true;
-
-    DartType futureRType = futureElement.type.instantiate([futureThenR.type]);
-    MethodElementImpl thenMethod = ElementFactory.methodElementWithParameters(
-        futureElement, "then", futureRType, [
-      ElementFactory.requiredParameter2("onValue", thenOnValue.type),
-      ElementFactory.namedParameter2("onError", provider.functionType)
-    ]);
-    if (!futureThenR.type.isDynamic) {
-      thenMethod.typeParameters = <TypeParameterElement>[futureThenR];
-    }
-    thenOnValue.enclosingElement = thenMethod;
-    thenOnValue.type = new FunctionTypeImpl(thenOnValue);
-    (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
-    thenMethod.type = new FunctionTypeImpl(thenMethod);
-
-    futureElement.methods = <MethodElement>[thenMethod];
-    // Completer
-    ClassElementImpl completerElement =
-        ElementFactory.classElement2("Completer", ["T"]);
-    ConstructorElementImpl completerConstructor =
-        ElementFactory.constructorElement2(completerElement, null);
-    completerElement.constructors = <ConstructorElement>[completerConstructor];
-    // StreamSubscription
-    ClassElementImpl streamSubscriptionElement =
-        ElementFactory.classElement2("StreamSubscription", ["T"]);
-    // Stream
-    ClassElementImpl streamElement =
-        ElementFactory.classElement2("Stream", ["T"]);
-    streamElement.isAbstract = true;
-    streamElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement2(streamElement, null)
-    ];
-    DartType returnType = streamSubscriptionElement.type
-        .instantiate(streamElement.type.typeArguments);
-    FunctionElementImpl listenOnData = ElementFactory.functionElement3(
-        'onData',
-        VoidTypeImpl.instance,
-        <TypeDefiningElement>[streamElement.typeParameters[0]],
-        null);
-    listenOnData.isSynthetic = true;
-    List<DartType> parameterTypes = <DartType>[
-      listenOnData.type,
-    ];
-    // TODO(brianwilkerson) This is missing the optional parameters.
-    MethodElementImpl listenMethod =
-        ElementFactory.methodElement('listen', returnType, parameterTypes);
-    streamElement.methods = <MethodElement>[listenMethod];
-    listenMethod.type = new FunctionTypeImpl(listenMethod);
-
-    FunctionElementImpl listenParamFunction = parameterTypes[0].element;
-    listenParamFunction.enclosingElement = listenMethod;
-    listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
-    ParameterElementImpl listenParam = listenMethod.parameters[0];
-    listenParam.type = listenParamFunction.type;
-
-    asyncUnit.types = <ClassElement>[
-      completerElement,
-      futureElement,
-      futureOrElement,
-      streamElement,
-      streamSubscriptionElement
-    ];
-    //
-    // dart:html
-    //
-    CompilationUnitElementImpl htmlUnit = new CompilationUnitElementImpl();
-    Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
-    htmlUnit.librarySource = htmlUnit.source = htmlSource;
-    ClassElementImpl elementElement = ElementFactory.classElement2("Element");
-    InterfaceType elementType = elementElement.type;
-    ClassElementImpl canvasElement =
-        ElementFactory.classElement("CanvasElement", elementType);
-    ClassElementImpl contextElement =
-        ElementFactory.classElement2("CanvasRenderingContext");
-    InterfaceType contextElementType = contextElement.type;
-    ClassElementImpl context2dElement = ElementFactory.classElement(
-        "CanvasRenderingContext2D", contextElementType);
-    canvasElement.methods = <MethodElement>[
-      ElementFactory.methodElement(
-          "getContext", contextElementType, [provider.stringType])
-    ];
-    canvasElement.accessors = <PropertyAccessorElement>[
-      ElementFactory.getterElement("context2D", false, context2dElement.type)
-    ];
-    canvasElement.fields = canvasElement.accessors
-        .map((PropertyAccessorElement accessor) => accessor.variable)
-        .cast<FieldElement>()
-        .toList();
-    ClassElementImpl documentElement =
-        ElementFactory.classElement("Document", elementType);
-    ClassElementImpl htmlDocumentElement =
-        ElementFactory.classElement("HtmlDocument", documentElement.type);
-    htmlDocumentElement.methods = <MethodElement>[
-      ElementFactory.methodElement(
-          "query", elementType, <DartType>[provider.stringType])
-    ];
-    htmlUnit.types = <ClassElement>[
-      ElementFactory.classElement("AnchorElement", elementType),
-      ElementFactory.classElement("BodyElement", elementType),
-      ElementFactory.classElement("ButtonElement", elementType),
-      canvasElement,
-      contextElement,
-      context2dElement,
-      ElementFactory.classElement("DivElement", elementType),
-      documentElement,
-      elementElement,
-      htmlDocumentElement,
-      ElementFactory.classElement("InputElement", elementType),
-      ElementFactory.classElement("SelectElement", elementType)
-    ];
-    htmlUnit.functions = <FunctionElement>[
-      ElementFactory.functionElement3("query", elementElement.type,
-          <ClassElement>[provider.stringType.element], const <ClassElement>[])
-    ];
-    TopLevelVariableElementImpl document =
-        ElementFactory.topLevelVariableElement3(
-            "document", false, true, htmlDocumentElement.type);
-    htmlUnit.topLevelVariables = <TopLevelVariableElement>[document];
-    htmlUnit.accessors = <PropertyAccessorElement>[document.getter];
-    LibraryElementImpl htmlLibrary = new LibraryElementImpl.forNode(
-        coreContext,
-        null,
-        AstTestFactory.libraryIdentifier2(["dart", "dom", "html"]),
-        featureSet.isEnabled(Feature.non_nullable));
-    htmlLibrary.definingCompilationUnit = htmlUnit;
-    //
-    // dart:math
-    //
-    CompilationUnitElementImpl mathUnit = new CompilationUnitElementImpl();
-    Source mathSource = sourceFactory.forUri(_DART_MATH);
-    mathUnit.librarySource = mathUnit.source = mathSource;
-    FunctionElement cosElement = ElementFactory.functionElement3(
-        "cos",
-        provider.doubleType,
-        <ClassElement>[provider.numType.element],
-        const <ClassElement>[]);
-    TopLevelVariableElement ln10Element =
-        ElementFactory.topLevelVariableElement3(
-            "LN10", true, false, provider.doubleType);
-    TypeParameterElement maxT =
-        ElementFactory.typeParameterWithType('T', provider.numType);
-    FunctionElementImpl maxElement = ElementFactory.functionElement3(
-        "max", maxT.type, [maxT, maxT], const <ClassElement>[]);
-    maxElement.typeParameters = [maxT];
-    maxElement.type = new FunctionTypeImpl(maxElement);
-    TopLevelVariableElement piElement = ElementFactory.topLevelVariableElement3(
-        "PI", true, false, provider.doubleType);
-    ClassElementImpl randomElement = ElementFactory.classElement2("Random");
-    randomElement.isAbstract = true;
-    ConstructorElementImpl randomConstructor =
-        ElementFactory.constructorElement2(randomElement, null);
-    randomConstructor.factory = true;
-    ParameterElementImpl seedParam = new ParameterElementImpl("seed", 0);
-    seedParam.parameterKind = ParameterKind.POSITIONAL;
-    seedParam.type = provider.intType;
-    randomConstructor.parameters = <ParameterElement>[seedParam];
-    randomElement.constructors = <ConstructorElement>[randomConstructor];
-    FunctionElement sinElement = ElementFactory.functionElement3(
-        "sin",
-        provider.doubleType,
-        <ClassElement>[provider.numType.element],
-        const <ClassElement>[]);
-    FunctionElement sqrtElement = ElementFactory.functionElement3(
-        "sqrt",
-        provider.doubleType,
-        <ClassElement>[provider.numType.element],
-        const <ClassElement>[]);
-    mathUnit.accessors = <PropertyAccessorElement>[
-      ln10Element.getter,
-      piElement.getter
-    ];
-    mathUnit.functions = <FunctionElement>[
-      cosElement,
-      maxElement,
-      sinElement,
-      sqrtElement
-    ];
-    mathUnit.topLevelVariables = <TopLevelVariableElement>[
-      ln10Element,
-      piElement
-    ];
-    mathUnit.types = <ClassElement>[randomElement];
-    LibraryElementImpl mathLibrary = new LibraryElementImpl.forNode(
-        coreContext,
-        null,
-        AstTestFactory.libraryIdentifier2(["dart", "math"]),
-        featureSet.isEnabled(Feature.non_nullable));
-    mathLibrary.definingCompilationUnit = mathUnit;
-    //
-    // Record the elements.
-    //
-    Map<Source, LibraryElement> elementMap =
-        new HashMap<Source, LibraryElement>();
-    elementMap[coreSource] = coreLibrary;
-    if (asyncSource != null) {
-      elementMap[asyncSource] = asyncLibrary;
-    }
-    elementMap[htmlSource] = htmlLibrary;
-    elementMap[mathSource] = mathLibrary;
-    //
-    // Set the public and export namespaces.  We don't use exports in the fake
-    // core library so public and export namespaces are the same.
-    //
-    for (LibraryElementImpl library in elementMap.values) {
-      Namespace namespace =
-          new NamespaceBuilder().createPublicNamespaceForLibrary(library);
-      library.exportNamespace = namespace;
-      library.publicNamespace = namespace;
-    }
-
-    context.typeProvider = SummaryTypeProvider()
-      ..initializeCore(coreLibrary)
-      ..initializeAsync(asyncLibrary);
-
-    // Create the synthetic element for `loadLibrary`.
-    for (LibraryElementImpl library in elementMap.values) {
-      library.createLoadLibraryFunction(context.typeProvider);
-    }
-    return context;
-  }
-}
-
-/**
- * An analysis context that has a fake SDK that is much smaller and faster for
- * testing purposes.
- */
-class AnalysisContextForTests extends AnalysisContextImpl {
-  @override
-  void set analysisOptions(AnalysisOptions options) {
-    AnalysisOptions currentOptions = analysisOptions;
-    bool needsRecompute = currentOptions.analyzeFunctionBodiesPredicate !=
-            options.analyzeFunctionBodiesPredicate ||
-        currentOptions.generateImplicitErrors !=
-            options.generateImplicitErrors ||
-        currentOptions.generateSdkErrors != options.generateSdkErrors ||
-        currentOptions.dart2jsHint != options.dart2jsHint ||
-        (currentOptions.hint && !options.hint) ||
-        currentOptions.preserveComments != options.preserveComments;
-    if (needsRecompute) {
-      fail(
-          "Cannot set options that cause the sources to be reanalyzed in a test context");
-    }
-    super.analysisOptions = options;
-  }
-
-  @override
-  bool exists(Source source) =>
-      super.exists(source) || sourceFactory.dartSdk.context.exists(source);
-
-  @override
-  TimestampedData<String> getContents(Source source) {
-    if (source.isInSystemLibrary) {
-      return sourceFactory.dartSdk.context.getContents(source);
-    }
-    return super.getContents(source);
-  }
-
-  @override
-  int getModificationStamp(Source source) {
-    if (source.isInSystemLibrary) {
-      return sourceFactory.dartSdk.context.getModificationStamp(source);
-    }
-    return super.getModificationStamp(source);
-  }
-
-  /**
-   * Set the analysis options, even if they would force re-analysis. This method should only be
-   * invoked before the fake SDK is initialized.
-   *
-   * @param options the analysis options to be set
-   */
-  void _internalSetAnalysisOptions(AnalysisOptions options) {
-    super.analysisOptions = options;
-  }
-}
-
-class TestPackageUriResolver extends UriResolver {
-  Map<String, Source> sourceMap = new HashMap<String, Source>();
-
-  TestPackageUriResolver(Map<String, String> map) {
-    map.forEach((String name, String contents) {
-      sourceMap['package:$name/$name.dart'] =
-          new StringSource(contents, '/$name/lib/$name.dart');
-    });
-  }
-
-  @override
-  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
-    String uriString = uri.toString();
-    return sourceMap[uriString];
-  }
-
-  @override
-  Uri restoreAbsolute(Source source) => throw new UnimplementedError();
-}
-
-class _AnalysisContextFactory_initContextWithCore extends FolderBasedDartSdk {
-  _AnalysisContextFactory_initContextWithCore(
-      ResourceProvider resourceProvider, String sdkPath)
-      : super(resourceProvider, resourceProvider.getFolder(sdkPath));
-
-  @override
-  LibraryMap initialLibraryMap(bool useDart2jsPaths) {
-    LibraryMap map = new LibraryMap();
-    _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
-    _addLibrary(map, DartSdk.DART_CORE, false, "core.dart");
-    _addLibrary(map, DartSdk.DART_HTML, false, "html_dartium.dart");
-    _addLibrary(map, AnalysisContextFactory._DART_MATH, false, "math.dart");
-    _addLibrary(map, AnalysisContextFactory._DART_INTERCEPTORS, true,
-        "_interceptors.dart");
-    _addLibrary(
-        map, AnalysisContextFactory._DART_JS_HELPER, true, "_js_helper.dart");
-    return map;
-  }
-
-  void _addLibrary(LibraryMap map, String uri, bool isInternal, String path) {
-    SdkLibraryImpl library = new SdkLibraryImpl(uri);
-    if (isInternal) {
-      library.category = "Internal";
-    }
-    library.path = path;
-    map.setLibrary(uri, library);
-  }
-}
diff --git a/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart b/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
index f92a108..4a90853 100644
--- a/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
@@ -55,7 +55,7 @@
 }
 var v = const A(null);
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 18, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 18, 10),
     ]);
   }
 
@@ -245,7 +245,7 @@
 }
 var v = const A('foo');
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 18, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 18, 10),
     ]);
   }
 
@@ -418,7 +418,7 @@
 }
 var v = const A('foo');
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 40, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
     ]);
   }
 
@@ -458,7 +458,7 @@
 }
 var v = const A(null);
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 40, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
     ]);
   }
 
@@ -523,7 +523,7 @@
 }
 var v = const A(null);
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 20, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 20, 10),
     ]);
   }
 
@@ -564,7 +564,7 @@
 }
 var v = const A('foo');
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 20, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 20, 10),
     ]);
   }
 
@@ -607,7 +607,7 @@
     await assertErrorsInCode('''
 const Unresolved x = null;
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 6, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 10),
     ]);
   }
 
@@ -624,7 +624,7 @@
     await assertErrorsInCode('''
 const Unresolved x = 'foo';
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 6, 10),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 10),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index 4e24a14..f4aad69 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -1690,10 +1690,10 @@
       await assertErrorsInCode(code, [
         // Due to dartbug.com/28515, some additional errors appear when using the
         // new analysis driver.
-        error(StaticWarningCode.UNDEFINED_CLASS, 7, 1),
+        error(CompileTimeErrorCode.UNDEFINED_CLASS, 7, 1),
         error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED, 7,
             11),
-        error(StaticWarningCode.UNDEFINED_CLASS, 14, 1),
+        error(CompileTimeErrorCode.UNDEFINED_CLASS, 14, 1),
       ]);
     }
   }
@@ -4938,7 +4938,7 @@
   return const A();
 }
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 21, 1),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 21, 1),
     ]);
   }
 
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 5a921b4..f74fe27 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -27,16 +26,13 @@
 
 import '../src/dart/resolution/driver_resolution.dart';
 import '../util/element_type_matchers.dart';
-import '../utils.dart';
-import 'analysis_context_factory.dart';
-import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
 import 'test_support.dart';
 
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnnotationElementResolverTest);
     defineReflectiveTests(ElementResolverTest);
-    defineReflectiveTests(PreviewDart2Test);
   });
 }
 
@@ -63,11 +59,10 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+      expect(name1.staticElement.displayName, 'A');
       expect(name2, isNotNull);
       expect(name2.staticElement, isConstructorElement);
-      expect(
-          resolutionMap.staticElementForIdentifier(name2).displayName, 'named');
+      expect(name2.staticElement.displayName, 'named');
       expect(name3, isNull);
       if (annotationElement is ConstructorElement) {
         expect(annotationElement, same(name2.staticElement));
@@ -93,14 +88,13 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isPrefixElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+      expect(name1.staticElement.displayName, 'p');
       expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+      expect(name2.staticElement.displayName, 'A');
       expect(name3, isNotNull);
       expect(name3.staticElement, isConstructorElement);
-      expect(
-          resolutionMap.staticElementForIdentifier(name3).displayName, 'named');
+      expect(name3.staticElement.displayName, 'named');
       if (annotationElement is ConstructorElement) {
         expect(annotationElement, same(name3.staticElement));
         expect(annotationElement.enclosingElement, name2.staticElement);
@@ -125,13 +119,13 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isPrefixElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+      expect(name1.staticElement.displayName, 'p');
       expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+      expect(name2.staticElement.displayName, 'A');
       expect(name3, isNotNull);
       expect(name3.staticElement, isPropertyAccessorElement);
-      expect(resolutionMap.staticElementForIdentifier(name3).displayName, 'V');
+      expect(name3.staticElement.displayName, 'V');
       if (annotationElement is PropertyAccessorElement) {
         expect(annotationElement, same(name3.staticElement));
         expect(annotationElement.enclosingElement, name2.staticElement);
@@ -155,10 +149,10 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isPrefixElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+      expect(name1.staticElement.displayName, 'p');
       expect(name2, isNotNull);
       expect(name2.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+      expect(name2.staticElement.displayName, 'A');
       expect(name3, isNull);
       if (annotationElement is ConstructorElement) {
         expect(annotationElement.enclosingElement, name2.staticElement);
@@ -183,10 +177,10 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+      expect(name1.staticElement.displayName, 'A');
       expect(name2, isNotNull);
       expect(name2.staticElement, isPropertyAccessorElement);
-      expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V');
+      expect(name2.staticElement.displayName, 'V');
       expect(name3, isNull);
       if (annotationElement is PropertyAccessorElement) {
         expect(annotationElement, same(name2.staticElement));
@@ -211,7 +205,7 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isClassElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+      expect(name1.staticElement.displayName, 'A');
       expect(name2, isNull);
       expect(name3, isNull);
       if (annotationElement is ConstructorElement) {
@@ -235,7 +229,7 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isPropertyAccessorElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'V');
+      expect(name1.staticElement.displayName, 'V');
       expect(name2, isNull);
       expect(name3, isNull);
       if (annotationElement is PropertyAccessorElement) {
@@ -259,10 +253,10 @@
         Element annotationElement) {
       expect(name1, isNotNull);
       expect(name1.staticElement, isPrefixElement);
-      expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+      expect(name1.staticElement.displayName, 'p');
       expect(name2, isNotNull);
       expect(name2.staticElement, isPropertyAccessorElement);
-      expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V');
+      expect(name2.staticElement.displayName, 'V');
       expect(name3, isNull);
       if (annotationElement is PropertyAccessorElement) {
         expect(annotationElement, same(name2.staticElement));
@@ -673,8 +667,7 @@
     parameterElement.type = intType;
     parameter.identifier.staticElement = parameterElement;
     _resolveInClass(parameter, classA);
-    expect(resolutionMap.elementDeclaredByFormalParameter(parameter).type,
-        same(intType));
+    expect(parameter.declaredElement.type, same(intType));
   }
 
   test_visitImportDirective_noCombinators_noPrefix() async {
@@ -727,36 +720,6 @@
     _listener.assertNoErrors();
   }
 
-  test_visitIndexExpression_get() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    InterfaceType intType = _typeProvider.intType;
-    MethodElement getter =
-        ElementFactory.methodElement("[]", intType, [intType]);
-    classA.methods = <MethodElement>[getter];
-    SimpleIdentifier array = AstTestFactory.identifier3("a");
-    array.staticType = classA.type;
-    IndexExpression expression =
-        AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i"));
-    expect(_resolveIndexExpression(expression), same(getter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitIndexExpression_set() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    InterfaceType intType = _typeProvider.intType;
-    MethodElement setter =
-        ElementFactory.methodElement("[]=", intType, [intType]);
-    classA.methods = <MethodElement>[setter];
-    SimpleIdentifier array = AstTestFactory.identifier3("a");
-    array.staticType = classA.type;
-    IndexExpression expression =
-        AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i"));
-    AstTestFactory.assignmentExpression(
-        expression, TokenType.EQ, AstTestFactory.integer(0));
-    expect(_resolveIndexExpression(expression), same(setter));
-    _listener.assertNoErrors();
-  }
-
   test_visitInstanceCreationExpression_named() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     String constructorName = "a";
@@ -1041,7 +1004,7 @@
 
   test_visitSimpleIdentifier_classScope() async {
     InterfaceType doubleType = _typeProvider.doubleType;
-    String fieldName = "NAN";
+    String fieldName = 'nan';
     SimpleIdentifier node = AstTestFactory.identifier3(fieldName);
     _resolveInClass(node, doubleType.element);
     expect(node.staticElement, getGetter(doubleType, fieldName));
@@ -1135,8 +1098,7 @@
    * Create and return the resolver used by the tests.
    */
   void _createResolver() {
-    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     _typeProvider = context.typeProvider;
 
     var inheritance = new InheritanceManager3(context.typeSystem);
@@ -1282,343 +1244,3 @@
     }
   }
 }
-
-@reflectiveTest
-class PreviewDart2Test extends ResolverTestCase {
-  @override
-  void setUp() {
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    resetWith(options: options);
-  }
-
-  /**
-   * Tests and verifies that even with a explicit 'new' keyword, the
-   * construction of the InstanceCreationExpression node with types and elements
-   * is all correct.
-   */
-  test_visitMethodInvocations_explicit() async {
-    String code = '''
-class A {
-  A() {}
-}
-main() {
-  new A();
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-
-    expect(creation.staticElement, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, isConstructorElement);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-  }
-
-  /**
-   * Test that the call to a constructor with an implicit unnamed constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * C()
-   */
-  test_visitMethodInvocations_implicit() async {
-    String code = '''
-class A {
-  A(a, {b}) {}
-}
-main() {
-  A(0, b: 1);
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-
-    List<Expression> arguments = creation.argumentList.arguments;
-    Expression argumentA = arguments[0];
-    expect(argumentA.staticParameterElement, constructor.parameters[0]);
-    NamedExpression argumentB = arguments[1];
-    expect(argumentB.name.label.staticElement, constructor.parameters[1]);
-  }
-
-  /**
-   * Test that the call to a constructor with an implicit unnamed constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * C(), where class C has no constructors
-   */
-  test_visitMethodInvocations_implicit_implicit() async {
-    String code = '''
-class A {}
-main() {
-  A();
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-
-    expect(creation.argumentList.arguments, isEmpty);
-  }
-
-  /**
-   * Test that the call to a constructor with an implicit named constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * C.n()
-   */
-  test_visitMethodInvocations_implicit_named() async {
-    String code = '''
-class A {
-  A.named() {}
-}
-main() {
-  A.named();
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name.staticElement, constructor);
-  }
-
-  /**
-   * Test that the call to a constructor with a prefixed implicit constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * p.C()
-   */
-  test_visitMethodInvocations_implicit_prefixed() async {
-    addNamedSource("/fileOne.dart", r'''
-class A {
-  A() {}
-}
-''');
-    String code = '''
-import 'fileOne.dart' as one;
-
-main() {
-  one.A();
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-  }
-
-  /**
-   * Test that the call to a constructor with a prefixed implicit named constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * p.C.n()
-   */
-  test_visitMethodInvocations_implicit_prefixed_named() async {
-    addNamedSource("/fileOne.dart", r'''
-class A {
-  A.named(a, {b}) {}
-}
-''');
-    String code = '''
-import 'fileOne.dart' as one;
-main() {
-  one.A.named(0, b: 1);
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name.staticElement, constructor);
-
-    List<Expression> arguments = creation.argumentList.arguments;
-    Expression argumentA = arguments[0];
-    expect(argumentA.staticParameterElement, constructor.parameters[0]);
-    NamedExpression argumentB = arguments[1];
-    expect(argumentB.name.label.staticElement, constructor.parameters[1]);
-  }
-
-  /**
-   * Test that the call to a constructor with a prefixed implicit constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * p.C<>()
-   */
-  test_visitMethodInvocations_implicit_prefixed_typeArgs() async {
-    addNamedSource("/fileOne.dart", r'''
-class A<T> {
-  final T x;
-  A(this.x) {}
-}
-''');
-    String code = '''
-import 'fileOne.dart' as one;
-
-main() {
-  one.A<int>(42);
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-  }
-
-  /**
-   * Test that the call to a constructor with an implicit unnamed constructor is
-   * re-written as an InstanceCreationExpression AST node from a
-   * MethodInvocation.
-   *
-   * C<>()
-   */
-  test_visitMethodInvocations_implicit_typeArgs() async {
-    String code = '''
-class A<T> {
-  final T x;
-  A(this.x) {}
-}
-main() {
-  A<int>(42);
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    InstanceCreationExpression creation = statement.expression;
-    ConstructorElement constructor = creation.staticElement;
-
-    expect(constructor, isConstructorElement);
-    expect(creation.staticType, isNotNull);
-
-    expect(creation.constructorName.staticElement, constructor);
-
-    expect(creation.constructorName.type.type, isNotNull);
-    expect(creation.constructorName.type.name.staticElement, isClassElement);
-
-    expect(creation.constructorName.name, isNull);
-  }
-
-  test_visitMethodInvocations_importPrefix_function() async {
-    String code = '''
-import 'dart:math' as ma;
-main() {
-  ma.max(1, 2); // marker
-}
-''';
-    CompilationUnit unit = await resolveSource(code);
-    var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
-    ExpressionStatement statement = statements[0];
-    MethodInvocation invocation = statement.expression;
-
-    SimpleIdentifier prefix = invocation.target;
-    expect(prefix.staticElement, isPrefixElement);
-
-    expect(invocation.methodName.name, 'max');
-  }
-
-  /**
-   * Test that the call to a static method will not be re-written as a
-   * InstanceCreationExpression AST node.
-   */
-  test_visitMethodInvocations_not_implicit_constructor() async {
-    String code = '''
-class A {
-  static staticMethod() {}
-}
-main() {
-  A.staticMethod(); // marker
-}
-    ''';
-    CompilationUnit unit = await resolveSource(code);
-    AstNode node = findMarkedIdentifier(code, unit, "(); // marker");
-    assert(node.parent is MethodInvocation);
-  }
-}
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index dfd1476..c183ac8 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -3,15 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/string_source.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisOptionsImplTest);
-    defineReflectiveTests(SourcesChangedEventTest);
   });
 }
 
@@ -62,74 +59,3 @@
         defaultOptions.trackCacheDependencies);
   }
 }
-
-@reflectiveTest
-class SourcesChangedEventTest {
-  void test_added() {
-    var source = new StringSource('', '/test.dart');
-    var changeSet = new ChangeSet();
-    changeSet.addedSource(source);
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event, wereSourcesAdded: true);
-  }
-
-  void test_changedContent() {
-    var source = new StringSource('', '/test.dart');
-    var changeSet = new ChangeSet();
-    changeSet.changedContent(source, 'library A;');
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event, changedSources: [source]);
-  }
-
-  void test_changedContent2() {
-    var source = new StringSource('', '/test.dart');
-    var event = new SourcesChangedEvent.changedContent(source, 'library A;');
-    assertEvent(event, changedSources: [source]);
-  }
-
-  void test_changedRange() {
-    var source = new StringSource('', '/test.dart');
-    var changeSet = new ChangeSet();
-    changeSet.changedRange(source, 'library A;', 0, 0, 13);
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event, changedSources: [source]);
-  }
-
-  void test_changedRange2() {
-    var source = new StringSource('', '/test.dart');
-    var event =
-        new SourcesChangedEvent.changedRange(source, 'library A;', 0, 0, 13);
-    assertEvent(event, changedSources: [source]);
-  }
-
-  void test_changedSources() {
-    var source = new StringSource('', '/test.dart');
-    var changeSet = new ChangeSet();
-    changeSet.changedSource(source);
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event, changedSources: [source]);
-  }
-
-  void test_empty() {
-    var changeSet = new ChangeSet();
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event);
-  }
-
-  void test_removed() {
-    var source = new StringSource('', '/test.dart');
-    var changeSet = new ChangeSet();
-    changeSet.removedSource(source);
-    var event = new SourcesChangedEvent(changeSet);
-    assertEvent(event, wereSourcesRemoved: true);
-  }
-
-  static void assertEvent(SourcesChangedEvent event,
-      {bool wereSourcesAdded: false,
-      List<Source> changedSources: const <Source>[],
-      bool wereSourcesRemoved: false}) {
-    expect(event.wereSourcesAdded, wereSourcesAdded);
-    expect(event.changedSources, changedSources);
-    expect(event.wereSourcesRemoved, wereSourcesRemoved);
-  }
-}
diff --git a/pkg/analyzer/test/generated/inheritance_manager_test.dart b/pkg/analyzer/test/generated/inheritance_manager_test.dart
index 8673c9e..881eb2c 100644
--- a/pkg/analyzer/test/generated/inheritance_manager_test.dart
+++ b/pkg/analyzer/test/generated/inheritance_manager_test.dart
@@ -19,7 +19,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -1110,8 +1110,7 @@
    */
   @deprecated
   InheritanceManager _createInheritanceManager() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     Source source = new FileSource(getFile("/test.dart"));
     CompilationUnitElementImpl definingCompilationUnit =
         new CompilationUnitElementImpl();
diff --git a/pkg/analyzer/test/generated/invalid_code_test.dart b/pkg/analyzer/test/generated/invalid_code_test.dart
index 9e7c84f..c77fa3e0 100644
--- a/pkg/analyzer/test/generated/invalid_code_test.dart
+++ b/pkg/analyzer/test/generated/invalid_code_test.dart
@@ -4,16 +4,32 @@
 
 import 'dart:async';
 
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../src/dart/resolution/driver_resolution.dart';
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(InvalidCodeTest);
+    if (AnalysisDriver.useSummary2) {
+      defineReflectiveTests(InvalidCodeSummary2Test);
+    } else {
+      defineReflectiveTests(InvalidCodeTest);
+    }
+    defineReflectiveTests(InvalidCodeWithExtensionMethodsTest);
   });
 }
 
+@reflectiveTest
+class InvalidCodeSummary2Test extends InvalidCodeTest {
+  @failingTest
+  test_fuzz_12() {
+    return test_fuzz_12();
+  }
+}
+
 /// Tests for various end-to-end cases when invalid code caused exceptions
 /// in one or another Analyzer subsystem. We are not interested not in specific
 /// errors generated, but we want to make sure that there is at least one,
@@ -115,6 +131,53 @@
 ''');
   }
 
+  test_fuzz_09() async {
+    await _assertCanBeAnalyzed(r'''
+typedef void F(int a, this.b);
+''');
+    var function = findElement.genericTypeAlias('F').function;
+    assertElementTypeString(
+      function.type,
+      'void Function(int, dynamic)',
+    );
+  }
+
+  test_fuzz_10() async {
+    await _assertCanBeAnalyzed(r'''
+void f<@A(() { Function() v; }) T>() {}
+''');
+  }
+
+  test_fuzz_11() async {
+    // Here `F` is a generic function, so it cannot be used as a bound for
+    // a type parameter. The reason it crashed was that we did not build
+    // the bound for `Y` (not `T`), because of the order in which types
+    // for `T extends F` and `typedef F` were built.
+    await _assertCanBeAnalyzed(r'''
+typedef F<X> = void Function<Y extends num>();
+class A<T extends F> {}
+''');
+  }
+
+  test_fuzz_12() async {
+    // This code crashed with summary2 because usually AST reader is lazy,
+    // so we did not read metadata `@b` for `c`. But default values must be
+    // read fully.
+    await _assertCanBeAnalyzed(r'''
+void f({a = [for (@b c = 0;;)]}) {}
+''');
+  }
+
+  test_fuzz_13() async {
+    // `x is int` promotes the type of `x` to `S extends int`, and the
+    // underlying element is `TypeParameterMember`, which by itself is
+    // questionable.  But this is not a valid constant anyway, so we should
+    // not even try to serialize it.
+    await _assertCanBeAnalyzed(r'''
+const v = [<S extends num>(S x) => x is int ? x : 0];
+''');
+  }
+
   test_genericFunction_asTypeArgument_ofUnresolvedClass() async {
     await _assertCanBeAnalyzed(r'''
 C<int Function()> c;
@@ -159,3 +222,28 @@
     assertHasTestErrors();
   }
 }
+
+@reflectiveTest
+class InvalidCodeWithExtensionMethodsTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_fuzz_14() async {
+    // This crashes because parser produces `ConstructorDeclaration`.
+    // So, we try to create `ConstructorElement` for it, and it wants
+    // `ClassElement` as the enclosing element. But we have `ExtensionElement`.
+    await _assertCanBeAnalyzed(r'''
+extension E {
+  factory S() {}
+}
+''');
+  }
+
+  Future<void> _assertCanBeAnalyzed(String text) async {
+    addTestFile(text);
+    await resolveTestFile();
+    assertHasTestErrors();
+  }
+}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 11fa1ce..729a4a0 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -793,8 +792,7 @@
 class E {}
 ''');
     CompilationUnit unit = result.unit;
-    ClassElement classC =
-        resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+    ClassElement classC = unit.declaredElement.getType('C');
     expect(classC.documentationComment, isNotNull);
   }
 
@@ -1894,8 +1892,7 @@
 class C extends A<B> with M {}
 ''');
     CompilationUnit unit = result.unit;
-    ClassElement classC =
-        resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+    ClassElement classC = unit.declaredElement.getType('C');
     expect(classC.mixins, hasLength(1));
     expect(classC.mixins[0].toString(), 'M<B>');
   }
@@ -1917,8 +1914,7 @@
       ),
     ]);
     CompilationUnit unit = result.unit;
-    ClassElement classC =
-        resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+    ClassElement classC = unit.declaredElement.getType('C');
     expect(classC.mixins, hasLength(1));
     expect(classC.mixins[0].toString(), 'M<int, String>');
   }
@@ -1934,8 +1930,7 @@
 class C extends A<List<B>> with M {}
 ''');
     CompilationUnit unit = result.unit;
-    ClassElement classC =
-        resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+    ClassElement classC = unit.declaredElement.getType('C');
     expect(classC.mixins, hasLength(1));
     expect(classC.mixins[0].toString(), 'M<B>');
   }
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index dd1a16f..f3145f8 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -32,34 +32,13 @@
 class ForwardingTestListener extends ForwardingListener {
   final _stack = <String>[];
 
+  ForwardingTestListener([Listener listener]) : super(listener);
+
   void begin(String event) {
     expect(event, isNotNull);
     _stack.add(event);
   }
 
-  void expectEmpty() {
-    expect(_stack, isEmpty);
-  }
-
-  void expectIn(String event) {
-    if (_stack.isEmpty || _stack.last != event) {
-      fail('Expected $event, but found $_stack');
-    }
-  }
-
-  void expectInOneOf(List<String> events) {
-    if (_stack.isEmpty || !events.contains(_stack.last)) {
-      fail('Expected one of $events, but found $_stack');
-    }
-  }
-
-  void end(String event) {
-    expectIn(event);
-    _stack.removeLast();
-  }
-
-  ForwardingTestListener([Listener listener]) : super(listener);
-
   @override
   void beginArguments(Token token) {
     super.beginArguments(token);
@@ -116,14 +95,14 @@
   }
 
   @override
-  void beginClassOrMixinBody(ClassKind kind, Token token) {
+  void beginClassOrMixinBody(DeclarationKind kind, Token token) {
     super.beginClassOrMixinBody(kind, token);
     begin('ClassOrMixinBody');
   }
 
   @override
-  void beginClassOrNamedMixinApplication(Token token) {
-    super.beginClassOrNamedMixinApplication(token);
+  void beginClassOrNamedMixinApplicationPrelude(Token token) {
+    super.beginClassOrNamedMixinApplicationPrelude(token);
     begin('ClassOrNamedMixinApplication');
   }
 
@@ -202,6 +181,12 @@
   }
 
   @override
+  void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+    super.beginExtensionDeclarationPrelude(extensionKeyword);
+    begin('ExtensionDeclarationPrelude');
+  }
+
+  @override
   void beginExtensionDeclaration(Token extensionKeyword, Token name) {
     super.beginExtensionDeclaration(extensionKeyword, name);
     begin('ExtensionDeclaration');
@@ -558,6 +543,11 @@
     begin('YieldStatement');
   }
 
+  void end(String event) {
+    expectIn(event);
+    _stack.removeLast();
+  }
+
   @override
   void endArguments(int count, Token beginToken, Token endToken) {
     end('Arguments');
@@ -579,13 +569,6 @@
   }
 
   @override
-  void endInvalidAwaitExpression(
-      Token beginToken, Token endToken, MessageCode errorCode) {
-    end('InvalidAwaitExpression');
-    super.endInvalidAwaitExpression(beginToken, endToken, errorCode);
-  }
-
-  @override
   void endBlock(int count, Token beginToken, Token endToken) {
     end('Block');
     super.endBlock(count, beginToken, endToken);
@@ -616,6 +599,14 @@
   }
 
   @override
+  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    end('Method');
+    super.endClassConstructor(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endClassDeclaration(Token beginToken, Token endToken) {
     end('ClassDeclaration');
     end('ClassOrNamedMixinApplication');
@@ -623,8 +614,32 @@
   }
 
   @override
+  void endClassFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    end('FactoryMethod');
+    super.endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    // beginMember --> endClassFields, endMember
+    expectIn('Member');
+    super.endClassFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    end('Method');
+    super.endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     end('ClassOrMixinBody');
     super.endClassOrMixinBody(kind, memberCount, beginToken, endToken);
   }
@@ -705,6 +720,14 @@
   }
 
   @override
+  void endExtensionConstructor(Token getOrSet, Token beginToken,
+      Token beginParam, Token beginInitializers, Token endToken) {
+    end('Method');
+    super.endExtensionConstructor(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endExtensionDeclaration(
       Token extensionKeyword, Token onKeyword, Token token) {
     super.endExtensionDeclaration(extensionKeyword, onKeyword, token);
@@ -712,10 +735,33 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endExtensionFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
     end('FactoryMethod');
-    super.endFactoryMethod(beginToken, factoryKeyword, endToken);
+    super.endExtensionFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endExtensionFields(
+      Token staticToken,
+      Token covariantToken,
+      Token lateToken,
+      Token varFinalOrConst,
+      int count,
+      Token beginToken,
+      Token endToken) {
+    // beginMember --> endExtensionFields, endMember
+    expectIn('Member');
+    super.endExtensionFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    end('Method');
+    super.endExtensionMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
 
   @override
@@ -725,15 +771,6 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
-      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
-    // beginMember --> endFields, endMember
-    expectIn('Member');
-    super.endFields(staticToken, covariantToken, lateToken, varFinalOrConst,
-        count, beginToken, endToken);
-  }
-
-  @override
   void endForControlFlow(Token token) {
     end('ForControlFlow');
     super.endForControlFlow(token);
@@ -876,6 +913,13 @@
   }
 
   @override
+  void endInvalidAwaitExpression(
+      Token beginToken, Token endToken, MessageCode errorCode) {
+    end('InvalidAwaitExpression');
+    super.endInvalidAwaitExpression(beginToken, endToken, errorCode);
+  }
+
+  @override
   void endLabeledStatement(int labelCount) {
     end('LabeledStatement');
     super.endLabeledStatement(labelCount);
@@ -924,10 +968,10 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     end('Method');
-    super.endMethod(
+    super.endMixinConstructor(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
 
@@ -939,6 +983,30 @@
   }
 
   @override
+  void endMixinFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    end('FactoryMethod');
+    super.endMixinFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    // beginMember --> endMixinFields, endMember
+    expectIn('Member');
+    super.endMixinFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    end('Method');
+    super.endMixinMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endNamedFunctionExpression(Token endToken) {
     end('NamedFunctionExpression');
     super.endNamedFunctionExpression(endToken);
@@ -1125,6 +1193,22 @@
     super.endYieldStatement(yieldToken, starToken, endToken);
   }
 
+  void expectEmpty() {
+    expect(_stack, isEmpty);
+  }
+
+  void expectIn(String event) {
+    if (_stack.isEmpty || _stack.last != event) {
+      fail('Expected $event, but found $_stack');
+    }
+  }
+
+  void expectInOneOf(List<String> events) {
+    if (_stack.isEmpty || !events.contains(_stack.last)) {
+      fail('Expected one of $events, but found $_stack');
+    }
+  }
+
   @override
   void handleClassExtends(Token extendsKeyword) {
     expectIn('ClassDeclaration');
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index e8674b8..0bc30b6 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -253,9 +253,6 @@
     createParser('late var f;', featureSet: nonNullable);
     ClassMember member = parser.parseClassMember('C');
     expect(member, isNotNull);
-    assertErrors(errors: [
-      expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 5, 3),
-    ]);
     expect(member, isFieldDeclaration);
     FieldDeclaration field = member;
     expect(field.covariantKeyword, isNull);
@@ -280,7 +277,7 @@
     ClassMember member = parser.parseClassMember('C');
     expect(member, isNotNull);
     assertErrors(errors: [
-      expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 4, 4),
+      expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 4, 4),
     ]);
     expect(member, isFieldDeclaration);
     FieldDeclaration field = member;
@@ -2611,6 +2608,17 @@
     parseCompilationUnit('main() { for(int? x in [7, null]) { } }');
   }
 
+  test_fuzz_38113() async {
+    // https://github.com/dart-lang/sdk/issues/38113
+    await parseCompilationUnit(r'+t{{r?this}}', errors: [
+      expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
+      expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 1, 1),
+      expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+      expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+      expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+    ]);
+  }
+
   void test_gft_nullable() {
     parseCompilationUnit('main() { C? Function() x = 7; }');
   }
@@ -2835,6 +2843,23 @@
     expect(target.operator.lexeme, '!');
   }
 
+  void test_nullCheckOnIndex2() {
+    // https://github.com/dart-lang/sdk/issues/37708
+    var unit = parseCompilationUnit('f() { obj![arg]![arg2]; }');
+    var funct = unit.declarations[0] as FunctionDeclaration;
+    var body = funct.functionExpression.body as BlockFunctionBody;
+    var statement = body.block.statements[0] as ExpressionStatement;
+    var expression = statement.expression as IndexExpression;
+    expect(expression.index.toSource(), 'arg2');
+    var target = expression.target as PostfixExpression;
+    expect(target.operator.lexeme, '!');
+    expression = target.operand as IndexExpression;
+    expect(expression.index.toSource(), 'arg');
+    target = expression.target as PostfixExpression;
+    expect(target.operator.lexeme, '!');
+    expect(target.operand.toSource(), 'obj');
+  }
+
   void test_nullCheckOnLiteral_disabled() {
     parseCompilationUnit('f() { var x = 0!; }',
         errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 15, 1)],
@@ -2888,6 +2913,23 @@
     expect(target.operator.lexeme, '!');
   }
 
+  void test_nullCheckOnSend2() {
+    // https://github.com/dart-lang/sdk/issues/37708
+    var unit = parseCompilationUnit('f() { obj!(arg)!(arg2); }');
+    var funct = unit.declarations[0] as FunctionDeclaration;
+    var body = funct.functionExpression.body as BlockFunctionBody;
+    var statement = body.block.statements[0] as ExpressionStatement;
+    var expression = statement.expression as FunctionExpressionInvocation;
+    expect(expression.argumentList.toSource(), '(arg2)');
+    var target = expression.function as PostfixExpression;
+    expect(target.operator.lexeme, '!');
+    expression = target.operand as FunctionExpressionInvocation;
+    expect(expression.argumentList.toSource(), '(arg)');
+    target = expression.function as PostfixExpression;
+    expect(target.operator.lexeme, '!');
+    expect(target.operand.toSource(), 'obj');
+  }
+
   void test_nullCheckOnSymbol() {
     // Issues like this should be caught during later analysis
     parseCompilationUnit('f() { var x = #seven!; }');
@@ -3299,6 +3341,17 @@
     expect(declarationList.variables, hasLength(1));
   }
 
+  void test_parseVariableDeclaration_late_var() {
+    var statement = parseStatement('late var a;', featureSet: nonNullable)
+        as VariableDeclarationStatement;
+    var declarationList = statement.variables;
+    assertNoErrors();
+    expect(declarationList.lateKeyword, isNotNull);
+    expect(declarationList.keyword?.lexeme, 'var');
+    expect(declarationList.type, isNull);
+    expect(declarationList.variables, hasLength(1));
+  }
+
   void test_typeAlias_37733() {
     // https://github.com/dart-lang/sdk/issues/37733
     var unit = parseCompilationUnit(r'typedef K=Function(<>($', errors: [
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index cca8618..584d201 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -5083,7 +5083,7 @@
     MethodInvocation methodInvocation = parseCascadeSection('..()');
     expectNotNullIfNoErrors(methodInvocation);
     listener.assertErrors([
-      // Cascade section is preceeded by `null` in this test
+      // Cascade section is preceded by `null` in this test
       // and error is reported on '('.
       expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1)
     ]);
@@ -5097,7 +5097,7 @@
     MethodInvocation methodInvocation = parseCascadeSection('..<E>()');
     expectNotNullIfNoErrors(methodInvocation);
     listener.assertErrors([
-      // Cascade section is preceeded by `null` in this test
+      // Cascade section is preceded by `null` in this test
       // and error is reported on '<'.
       expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1)
     ]);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 663ec18..0b7c771 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -17,6 +16,7 @@
 import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
@@ -26,15 +26,14 @@
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/source/source_resource.dart';
-import 'package:analyzer/src/string_source.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../src/dart/resolution/driver_resolution.dart';
-import 'analysis_context_factory.dart';
 import 'parser_test.dart';
 import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
 import 'test_support.dart';
 
 main() {
@@ -50,7 +49,6 @@
     defineReflectiveTests(ScopeTest);
     defineReflectiveTests(StrictModeTest);
     defineReflectiveTests(TypePropagationTest);
-    defineReflectiveTests(TypeProviderImplTest);
     defineReflectiveTests(TypeResolverVisitorTest);
   });
 }
@@ -255,8 +253,7 @@
   }
 
   void test_creation_nonEmpty() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     String importedTypeName = "A";
     ClassElement importedType = new ClassElementImpl.forNode(
         AstTestFactory.identifier3(importedTypeName));
@@ -276,8 +273,7 @@
   }
 
   void test_extensions_imported() {
-    var context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    var context = TestAnalysisContext();
 
     var extension = ElementFactory.extensionElement('test_extension');
 
@@ -304,8 +300,7 @@
   }
 
   void test_prefixedAndNonPrefixed() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     String typeName = "C";
     String prefixName = "p";
     ClassElement prefixedType = ElementFactory.classElement2(typeName);
@@ -345,8 +340,7 @@
   }
 
   void test_creation_nonEmpty() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     String importedTypeName = "A";
     ClassElement importedType = new ClassElementImpl.forNode(
         AstTestFactory.identifier3(importedTypeName));
@@ -382,8 +376,7 @@
   }
 
   void test_extensions_imported() {
-    var context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    var context = TestAnalysisContext();
 
     var importedUnit1 = ElementFactory.compilationUnit('/imported1.dart');
     var importedExtension = ElementFactory.extensionElement('test_extension');
@@ -419,8 +412,7 @@
   /// Ensure that if a library L1 defines an extension E, L2 exports L1, and L3
   /// imports L2, then E is included in the list.
   void test_extensions_imported_chain() {
-    var context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    var context = TestAnalysisContext();
 
     var unit1 = ElementFactory.compilationUnit('/unit1.dart');
     var ext1 = ElementFactory.extensionElement('ext1');
@@ -462,8 +454,7 @@
   /// imported from different libraries that they are both in the list of
   /// extensions.
   void test_extensions_imported_same_name() {
-    var context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    var context = TestAnalysisContext();
 
     var sharedExtensionName = 'test_ext';
 
@@ -507,8 +498,7 @@
   /// Ensure that if there are two imports for the same library that the
   /// imported extension is only in the list one time.
   void test_extensions_imported_twice() {
-    var context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    var context = TestAnalysisContext();
 
     var sharedExtensionName = 'test_ext';
 
@@ -611,8 +601,11 @@
     //
     // Create a type provider and ensure that it can return the expected types.
     //
-    TypeProvider provider =
-        new NonNullableTypeProvider(coreLibrary, asyncLibrary);
+    TypeProvider provider = new TypeProviderImpl(
+      coreLibrary,
+      asyncLibrary,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
     assertNonNullable(provider.boolType);
     expect(provider.bottomType, isNotNull);
     assertNonNullable(provider.deprecatedType);
@@ -822,8 +815,7 @@
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     // In cases where we have a prefixed identifier where the prefix is dynamic,
     // we don't want to assert that the node will have a type.
-    if (node.staticType == null &&
-        resolutionMap.staticTypeForExpression(node.prefix).isDynamic) {
+    if (node.staticType == null && node.prefix.staticType.isDynamic) {
       return;
     }
     super.visitPrefixedIdentifier(node);
@@ -885,10 +877,7 @@
       if (root is CompilationUnit) {
         CompilationUnit rootCU = root;
         if (rootCU.declaredElement != null) {
-          return resolutionMap
-              .elementDeclaredByCompilationUnit(rootCU)
-              .source
-              .fullName;
+          return rootCU.declaredElement.source.fullName;
         } else {
           return "<unknown file- CompilationUnit.getElement() returned null>";
         }
@@ -1342,116 +1331,6 @@
 }
 
 @reflectiveTest
-class TypeProviderImplTest extends EngineTestCase {
-  void test_creation() {
-    //
-    // Create a mock library element with the types expected to be in dart:core.
-    // We cannot use either ElementFactory or TestTypeProvider (which uses
-    // ElementFactory) because we side-effect the elements in ways that would
-    // break other tests.
-    //
-    InterfaceType objectType = _classElement("Object", null).type;
-    InterfaceType boolType = _classElement("bool", objectType).type;
-    InterfaceType numType = _classElement("num", objectType).type;
-    InterfaceType doubleType = _classElement("double", numType).type;
-    InterfaceType functionType = _classElement("Function", objectType).type;
-    InterfaceType futureType = _classElement("Future", objectType, ["T"]).type;
-    InterfaceType futureOrType =
-        _classElement("FutureOr", objectType, ["T"]).type;
-    InterfaceType intType = _classElement("int", numType).type;
-    InterfaceType iterableType =
-        _classElement("Iterable", objectType, ["T"]).type;
-    InterfaceType listType = _classElement("List", objectType, ["E"]).type;
-    InterfaceType mapType = _classElement("Map", objectType, ["K", "V"]).type;
-    InterfaceType setType = _classElement("Set", objectType, ["E"]).type;
-    InterfaceType stackTraceType = _classElement("StackTrace", objectType).type;
-    InterfaceType streamType = _classElement("Stream", objectType, ["T"]).type;
-    InterfaceType stringType = _classElement("String", objectType).type;
-    InterfaceType symbolType = _classElement("Symbol", objectType).type;
-    InterfaceType typeType = _classElement("Type", objectType).type;
-    CompilationUnitElementImpl coreUnit = new CompilationUnitElementImpl();
-    coreUnit.types = <ClassElement>[
-      boolType.element,
-      doubleType.element,
-      functionType.element,
-      intType.element,
-      iterableType.element,
-      listType.element,
-      mapType.element,
-      setType.element,
-      objectType.element,
-      stackTraceType.element,
-      stringType.element,
-      symbolType.element,
-      typeType.element
-    ];
-    coreUnit.source = new StringSource('', null, uri: Uri.parse('dart:core'));
-    coreUnit.librarySource = coreUnit.source;
-    CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
-    asyncUnit.types = <ClassElement>[
-      futureType.element,
-      futureOrType.element,
-      streamType.element
-    ];
-
-    asyncUnit.source = new StringSource('', null, uri: Uri.parse('dart:async'));
-    asyncUnit.librarySource = asyncUnit.source;
-    LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
-        null, null, AstTestFactory.libraryIdentifier2(["dart.core"]), true);
-    coreLibrary.definingCompilationUnit = coreUnit;
-    LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
-        null, null, AstTestFactory.libraryIdentifier2(["dart.async"]), true);
-    asyncLibrary.definingCompilationUnit = asyncUnit;
-    //
-    // Create a type provider and ensure that it can return the expected types.
-    //
-    TypeProviderImpl provider = new TypeProviderImpl(coreLibrary, asyncLibrary);
-    expect(provider.boolType, same(boolType));
-    expect(provider.bottomType, isNotNull);
-    expect(provider.doubleType, same(doubleType));
-    expect(provider.dynamicType, isNotNull);
-    expect(provider.functionType, same(functionType));
-    expect(provider.futureType, same(futureType));
-    expect(provider.futureOrType, same(futureOrType));
-    expect(provider.intType, same(intType));
-    expect(provider.listType, same(listType));
-    expect(provider.mapType, same(mapType));
-    expect(provider.objectType, same(objectType));
-    expect(provider.stackTraceType, same(stackTraceType));
-    expect(provider.streamType, same(streamType));
-    expect(provider.stringType, same(stringType));
-    expect(provider.symbolType, same(symbolType));
-    expect(provider.typeType, same(typeType));
-  }
-
-  ClassElement _classElement(String typeName, InterfaceType superclassType,
-      [List<String> parameterNames]) {
-    ClassElementImpl element =
-        new ClassElementImpl.forNode(AstTestFactory.identifier3(typeName));
-    element.supertype = superclassType;
-    if (parameterNames != null) {
-      int count = parameterNames.length;
-      if (count > 0) {
-        List<TypeParameterElementImpl> typeParameters =
-            new List<TypeParameterElementImpl>(count);
-        List<TypeParameterTypeImpl> typeArguments =
-            new List<TypeParameterTypeImpl>(count);
-        for (int i = 0; i < count; i++) {
-          TypeParameterElementImpl typeParameter =
-              new TypeParameterElementImpl.forNode(
-                  AstTestFactory.identifier3(parameterNames[i]));
-          typeParameters[i] = typeParameter;
-          typeArguments[i] = new TypeParameterTypeImpl(typeParameter);
-          typeParameter.type = typeArguments[i];
-        }
-        element.typeParameters = typeParameters;
-      }
-    }
-    return element;
-  }
-}
-
-@reflectiveTest
 class TypeResolverVisitorTest extends ParserTestCase
     with ResourceProviderMixin {
   /**
@@ -1497,8 +1376,7 @@
 
   void setUp({bool shouldSetElementSupertypes: false}) {
     _listener = new GatheringErrorListener();
-    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: resourceProvider);
+    AnalysisContext context = TestAnalysisContext();
     Source librarySource = new FileSource(getFile("/lib.dart"));
     // TODO(paulberry): make it possible to override the feature set so we can
     // test NNBD features.
@@ -1542,8 +1420,7 @@
 
     // Resolve API types.
     {
-      InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
-          resourceProvider: resourceProvider);
+      AnalysisContext context = TestAnalysisContext();
       var source = getFile('/test.dart').createSource();
       // TODO(paulberry): make it possible to override the feature set so we can
       // test NNBD features.
@@ -2288,7 +2165,7 @@
     _resolveNode(typeName, []);
     expect(typeName.type, DynamicTypeImpl.instance);
     expect(typeName.name.staticElement, null);
-    _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+    _listener.assertErrorsWithCodes([CompileTimeErrorCode.UNDEFINED_CLASS]);
   }
 
   test_visitTypeName_parameters_arguments() async {
@@ -2334,7 +2211,7 @@
     expect(typeName.type, DynamicTypeImpl.instance);
     expect(prefix.staticElement, null);
     expect(suffix.staticElement, null);
-    _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+    _listener.assertErrorsWithCodes([CompileTimeErrorCode.UNDEFINED_CLASS]);
   }
 
   test_visitTypeName_void() async {
@@ -2423,8 +2300,7 @@
     LibraryScope libraryScope;
     TypeResolverVisitor visitor;
     {
-      InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
-          resourceProvider: resourceProvider);
+      AnalysisContext context = TestAnalysisContext();
       var source = getFile('/test.dart').createSource();
       // TODO(paulberry): make it possible to override the feature set so we can
       // test NNBD features.
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index 9c5ba4f..fdb3b15 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -33,7 +32,7 @@
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:test/test.dart';
 
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
 import 'test_support.dart';
 
 const String _defaultSourceName = "/test.dart";
@@ -245,8 +244,8 @@
     if (node.name == "void") {
       return;
     }
-    if (resolutionMap.staticTypeForExpression(node) != null &&
-        resolutionMap.staticTypeForExpression(node).isDynamic &&
+    if (node.staticType != null &&
+        node.staticType.isDynamic &&
         node.staticElement == null) {
       return;
     }
@@ -285,10 +284,7 @@
       if (root is CompilationUnit) {
         CompilationUnit rootCU = root;
         if (rootCU.declaredElement != null) {
-          return resolutionMap
-              .elementDeclaredByCompilationUnit(rootCU)
-              .source
-              .fullName;
+          return rootCU.declaredElement.source.fullName;
         } else {
           return "<unknown file- CompilationUnit.getElement() returned null>";
         }
@@ -521,10 +517,8 @@
    *
    * @return the library element that was created
    */
-  LibraryElementImpl createDefaultTestLibrary() => createTestLibrary(
-      AnalysisContextFactory.contextWithCore(
-          resourceProvider: resourceProvider),
-      "test");
+  LibraryElementImpl createDefaultTestLibrary() =>
+      createTestLibrary(TestAnalysisContext(), "test");
 
   /**
    * Return a source object representing a file with the given [fileName].
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index aad0e06..de9c1f3 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -12,10 +12,8 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/static_type_analyzer.dart';
@@ -27,8 +25,8 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'analysis_context_factory.dart';
 import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
 import 'test_support.dart';
 
 main() {
@@ -429,26 +427,6 @@
     _listener.assertNoErrors();
   }
 
-  void test_visitAssignmentExpression_compound_II() {
-    validate(TokenType operator) {
-      InterfaceType numType = _typeProvider.numType;
-      InterfaceType intType = _typeProvider.intType;
-      SimpleIdentifier identifier = _resolvedVariable(intType, "i");
-      AssignmentExpression node = AstTestFactory.assignmentExpression(
-          identifier, operator, _resolvedInteger(1));
-      MethodElement plusMethod = getMethod(numType, "+");
-      node.staticElement = plusMethod;
-      expect(_analyze(node), same(intType));
-      _listener.assertNoErrors();
-    }
-
-    validate(TokenType.MINUS_EQ);
-    validate(TokenType.PERCENT_EQ);
-    validate(TokenType.PLUS_EQ);
-    validate(TokenType.STAR_EQ);
-    validate(TokenType.TILDE_SLASH_EQ);
-  }
-
   void test_visitAssignmentExpression_compound_lazy() {
     validate(TokenType operator) {
       InterfaceType boolType = _typeProvider.boolType;
@@ -463,46 +441,6 @@
     validate(TokenType.BAR_BAR_EQ);
   }
 
-  void test_visitAssignmentExpression_compound_plusID() {
-    validate(TokenType operator) {
-      InterfaceType numType = _typeProvider.numType;
-      InterfaceType intType = _typeProvider.intType;
-      InterfaceType doubleType = _typeProvider.doubleType;
-      SimpleIdentifier identifier = _resolvedVariable(intType, "i");
-      AssignmentExpression node = AstTestFactory.assignmentExpression(
-          identifier, operator, _resolvedDouble(1.0));
-      MethodElement plusMethod = getMethod(numType, "+");
-      node.staticElement = plusMethod;
-      expect(_analyze(node), same(doubleType));
-      _listener.assertNoErrors();
-    }
-
-    validate(TokenType.MINUS_EQ);
-    validate(TokenType.PERCENT_EQ);
-    validate(TokenType.PLUS_EQ);
-    validate(TokenType.STAR_EQ);
-  }
-
-  void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
-    // double d; d ??= 0
-    Expression node = AstTestFactory.assignmentExpression(
-        _resolvedVariable(_typeProvider.doubleType, 'd'),
-        TokenType.QUESTION_QUESTION_EQ,
-        _resolvedInteger(0));
-    expect(_analyze(node), _typeProvider.numType);
-    _listener.assertNoErrors();
-  }
-
-  void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
-    // int i; i ??= 0
-    Expression node = AstTestFactory.assignmentExpression(
-        _resolvedVariable(_typeProvider.intType, 'i'),
-        TokenType.QUESTION_QUESTION_EQ,
-        _resolvedInteger(0));
-    expect(_analyze(node), same(_typeProvider.intType));
-    _listener.assertNoErrors();
-  }
-
   void test_visitAssignmentExpression_simple() {
     // i = 0
     InterfaceType intType = _typeProvider.intType;
@@ -604,7 +542,7 @@
         _resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
     node.staticElement = getMethod(_typeProvider.numType, "/");
     node.staticInvokeType = node.staticElement.type;
-    expect(_analyze(node), same(_typeProvider.doubleType));
+    expect(_analyze(node), _typeProvider.doubleType);
     _listener.assertNoErrors();
   }
 
@@ -981,79 +919,6 @@
     _listener.assertNoErrors();
   }
 
-  void test_visitIndexExpression_getter() {
-    // List a;
-    // a[2]
-    InterfaceType listType = _typeProvider.listType;
-    SimpleIdentifier identifier = _resolvedVariable(listType, "a");
-    IndexExpression node =
-        AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
-    MethodElement indexMethod = listType.element.methods[0];
-    node.staticElement = indexMethod;
-    expect(_analyze(node), same(listType.typeArguments[0]));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitIndexExpression_setter() {
-    // List a;
-    // a[2] = 0
-    InterfaceType listType = _typeProvider.listType;
-    SimpleIdentifier identifier = _resolvedVariable(listType, "a");
-    IndexExpression node =
-        AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
-    MethodElement indexMethod = listType.element.methods[1];
-    node.staticElement = indexMethod;
-    AstTestFactory.assignmentExpression(
-        node, TokenType.EQ, AstTestFactory.integer(0));
-    expect(_analyze(node), same(listType.typeArguments[0]));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitIndexExpression_typeParameters() {
-    // List<int> list = ...
-    // list[0]
-    InterfaceType intType = _typeProvider.intType;
-    InterfaceType listType = _typeProvider.listType;
-    // (int) -> E
-    MethodElement methodElement = getMethod(listType, "[]");
-    // "list" has type List<int>
-    SimpleIdentifier identifier = AstTestFactory.identifier3("list");
-    InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
-    identifier.staticType = listOfIntType;
-    // list[0] has MethodElement element (int) -> E
-    IndexExpression indexExpression =
-        AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
-    MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
-    indexExpression.staticElement = indexMethod;
-    // analyze and assert result of the index expression
-    expect(_analyze(indexExpression), same(intType));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitIndexExpression_typeParameters_inSetterContext() {
-    // List<int> list = ...
-    // list[0] = 0;
-    InterfaceType intType = _typeProvider.intType;
-    InterfaceType listType = _typeProvider.listType;
-    // (int, E) -> void
-    MethodElement methodElement = getMethod(listType, "[]=");
-    // "list" has type List<int>
-    SimpleIdentifier identifier = AstTestFactory.identifier3("list");
-    InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
-    identifier.staticType = listOfIntType;
-    // list[0] has MethodElement element (int) -> E
-    IndexExpression indexExpression =
-        AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
-    MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
-    indexExpression.staticElement = indexMethod;
-    // list[0] should be in a setter context
-    AstTestFactory.assignmentExpression(
-        indexExpression, TokenType.EQ, AstTestFactory.integer(0));
-    // analyze and assert result of the index expression
-    expect(_analyze(indexExpression), same(intType));
-    _listener.assertNoErrors();
-  }
-
   void test_visitInstanceCreationExpression_named() {
     // new C.m()
     ClassElementImpl classElement = ElementFactory.classElement2("C");
@@ -1150,7 +1015,6 @@
   }
 
   void test_visitListLiteral_unresolved() {
-    _analyzer = _createAnalyzer(strongMode: true);
     // [a] // where 'a' is not resolved
     Identifier identifier = AstTestFactory.identifier3('a');
     Expression node = AstTestFactory.listLiteral([identifier]);
@@ -1163,7 +1027,6 @@
   }
 
   void test_visitListLiteral_unresolved_multiple() {
-    _analyzer = _createAnalyzer(strongMode: true);
     // [0, a, 1] // where 'a' is not resolved
     Identifier identifier = AstTestFactory.identifier3('a');
     Expression node = AstTestFactory.listLiteral(
@@ -1288,7 +1151,7 @@
         AstTestFactory.prefixExpression(TokenType.MINUS, _resolvedInteger(0));
     MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
     node.staticElement = minusMethod;
-    expect(_analyze(node), same(_typeProvider.numType));
+    expect(_analyze(node), _typeProvider.numType);
     _listener.assertNoErrors();
   }
 
@@ -1326,7 +1189,7 @@
         AstTestFactory.prefixExpression(TokenType.TILDE, _resolvedInteger(0));
     MethodElement tildeMethod = getMethod(_typeProvider.intType, "~");
     node.staticElement = tildeMethod;
-    expect(_analyze(node), same(_typeProvider.intType));
+    expect(_analyze(node), _typeProvider.intType);
     _listener.assertNoErrors();
   }
 
@@ -1514,16 +1377,8 @@
   /**
    * Create the analyzer used by the tests.
    */
-  StaticTypeAnalyzer _createAnalyzer({bool strongMode: false}) {
-    InternalAnalysisContext context;
-    if (strongMode) {
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-      context = AnalysisContextFactory.contextWithCoreAndOptions(options,
-          resourceProvider: resourceProvider);
-    } else {
-      context = AnalysisContextFactory.contextWithCore(
-          resourceProvider: resourceProvider);
-    }
+  StaticTypeAnalyzer _createAnalyzer() {
+    var context = TestAnalysisContext();
     var inheritance = new InheritanceManager3(context.typeSystem);
     Source source = new FileSource(getFile("/lib.dart"));
     CompilationUnitElementImpl definingCompilationUnit =
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index 2db6cba..0cfcdb3 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -422,7 +422,7 @@
     await assertErrorsInCode('''
 f() { new C(); }
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 10, 1),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 10, 1),
     ]);
   }
 
@@ -430,7 +430,7 @@
     await assertErrorsInCode('''
 f() { C c; }
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 6, 1),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 1),
       error(HintCode.UNUSED_LOCAL_VARIABLE, 8, 1),
     ]);
   }
@@ -549,7 +549,7 @@
 main() {
   f(c: 1);
 }''', [
-      error(StaticWarningCode.UNDEFINED_NAMED_PARAMETER, 26, 1),
+      error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 26, 1),
     ]);
   }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index a8e32bf..4970fc2 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
@@ -1821,8 +1820,7 @@
     InstanceCreationExpression exp = stmt.expression;
     ClassElement elementB = AstFinder.getClass(unit, "B").declaredElement;
     ClassElement elementA = AstFinder.getClass(unit, "A").declaredElement;
-    expect(resolutionMap.typeForTypeName(exp.constructorName.type).element,
-        elementB);
+    expect(exp.constructorName.type.type.element, elementB);
     _isInstantiationOf(_hasElement(elementB))(
         [_isType(elementA.typeParameters[0].type)])(exp.staticType);
   }
@@ -1874,8 +1872,7 @@
     expect(type0.normalParameterTypes[0], typeProvider.stringType);
 
     FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
-    FunctionType type1 =
-        resolutionMap.elementDeclaredByFunctionExpression(anon1).type;
+    FunctionType type1 = anon1.declaredElement.type;
     expect(type1.returnType, typeProvider.intType);
     expect(type1.normalParameterTypes[0], typeProvider.intType);
   }
@@ -1899,7 +1896,7 @@
       VariableDeclarationStatement stmt = statements[i];
       VariableDeclaration decl = stmt.variables.variables[0];
       FunctionExpression exp = decl.initializer;
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -1928,7 +1925,7 @@
       VariableDeclarationStatement stmt = statements[i];
       VariableDeclaration decl = stmt.variables.variables[0];
       FunctionExpression exp = decl.initializer;
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -1993,7 +1990,7 @@
       ExpressionStatement stmt = statements[i];
       FunctionExpressionInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2024,7 +2021,7 @@
       ExpressionStatement stmt = statements[i];
       FunctionExpressionInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2053,7 +2050,7 @@
       ExpressionStatement stmt = statements[i];
       MethodInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2082,7 +2079,7 @@
       ExpressionStatement stmt = statements[i];
       MethodInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2113,7 +2110,7 @@
       ExpressionStatement stmt = statements[i];
       MethodInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2144,7 +2141,7 @@
       ExpressionStatement stmt = statements[i];
       MethodInvocation invk = stmt.expression;
       FunctionExpression exp = invk.argumentList.arguments[0];
-      return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+      return exp.declaredElement.type;
     }
 
     _isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2847,10 +2844,8 @@
 
     VariableDeclaration mapB = AstFinder.getFieldInClass(unit, "B", "map");
     MethodDeclaration mapC = AstFinder.getMethodInClass(unit, "C", "map");
-    assertMapOfIntToListOfInt(
-        resolutionMap.elementDeclaredByVariableDeclaration(mapB).type);
-    assertMapOfIntToListOfInt(
-        resolutionMap.elementDeclaredByMethodDeclaration(mapC).returnType);
+    assertMapOfIntToListOfInt(mapB.declaredElement.type);
+    assertMapOfIntToListOfInt(mapC.declaredElement.returnType);
 
     SetOrMapLiteral mapLiteralB = mapB.initializer;
     SetOrMapLiteral mapLiteralC =
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index e6af823..f4d11a7 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -8,6 +8,7 @@
 import 'checked_mode_compile_time_error_code_test.dart'
     as checked_mode_compile_time_error_code;
 import 'compile_time_error_code_test.dart' as compile_time_error_code;
+// ignore: deprecated_member_use_from_same_package
 import 'constant_test.dart' as constant_test;
 import 'declaration_resolver_test.dart' as declaration_resolver_test;
 import 'element_resolver_test.dart' as element_resolver_test;
diff --git a/pkg/analyzer/test/generated/test_analysis_context.dart b/pkg/analyzer/test/generated/test_analysis_context.dart
new file mode 100644
index 0000000..3c6918f
--- /dev/null
+++ b/pkg/analyzer/test/generated/test_analysis_context.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk_elements.dart';
+
+class TestAnalysisContext implements AnalysisContext {
+  @override
+  final SourceFactory sourceFactory = _MockSourceFactory();
+
+  AnalysisOptions _analysisOptions;
+  TypeProvider _typeProvider;
+  TypeSystem _typeSystem;
+
+  TestAnalysisContext({FeatureSet featureSet}) {
+    _analysisOptions = AnalysisOptionsImpl()
+      ..contextFeatures = featureSet ?? FeatureSet.forTesting();
+
+    var sdkElements = MockSdkElements(
+      this,
+      analysisOptions.contextFeatures.isEnabled(Feature.non_nullable)
+          ? NullabilitySuffix.none
+          : NullabilitySuffix.star,
+    );
+
+    _typeProvider = TypeProviderImpl(
+      sdkElements.coreLibrary,
+      sdkElements.asyncLibrary,
+    );
+    _typeSystem = Dart2TypeSystem(typeProvider);
+  }
+
+  @override
+  AnalysisOptions get analysisOptions => _analysisOptions;
+
+  @override
+  TypeProvider get typeProvider => _typeProvider;
+
+  @override
+  TypeSystem get typeSystem => _typeSystem;
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSource implements Source {
+  @override
+  final Uri uri;
+
+  _MockSource(this.uri);
+
+  @override
+  String get encoding => '$uri';
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSourceFactory implements SourceFactory {
+  @override
+  Source forUri(String uriStr) {
+    var uri = Uri.parse(uriStr);
+    return _MockSource(uri);
+  }
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 2a05d30..f85b302 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
@@ -17,7 +16,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:test/test.dart';
 
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
 
 /// The class `EngineTestCase` defines utility methods for making assertions.
 class EngineTestCase {
@@ -53,8 +52,7 @@
   }
 
   AnalysisContext createAnalysisContext() {
-    return AnalysisContextFactory.contextWithCore(
-        resourceProvider: new MemoryResourceProvider());
+    return TestAnalysisContext();
   }
 
   /// Return the getter in the given [type] with the given [name]. Inherited
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 16f0d8d..6e6cd92 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -10,10 +10,10 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/dart/ast/token.dart' show KeywordToken;
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -27,7 +27,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -380,9 +380,8 @@
   DartType get voidType => VoidTypeImpl.instance;
 
   void setUp() {
-    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
-        resourceProvider: new MemoryResourceProvider());
-    typeProvider = context.typeProvider;
+    var analysisContext = TestAnalysisContext();
+    typeProvider = analysisContext.typeProvider;
     var simpleFunctionElement =
         ElementFactory.genericTypeAliasElement('A', returnType: voidType);
     simpleFunctionType = simpleFunctionElement.type;
@@ -537,10 +536,9 @@
   DartType list(DartType T) => typeProvider.listType.instantiate([T]);
 
   void setUp() {
-    typeProvider = AnalysisContextFactory.contextWithCore(
-            resourceProvider: new MemoryResourceProvider())
-        .typeProvider;
-    typeSystem = new Dart2TypeSystem(typeProvider);
+    var analysisContext = TestAnalysisContext();
+    typeProvider = analysisContext.typeProvider;
+    typeSystem = analysisContext.typeSystem;
     T = _newTypeParameter('T');
   }
 
@@ -945,19 +943,19 @@
   }
 
   void test_boundedRecursively() {
-    // class Clonable<T extends Clonable<T>>
-    ClassElementImpl clonable =
-        ElementFactory.classElement('Clonable', objectType, ['T']);
-    (clonable.typeParameters[0] as TypeParameterElementImpl).bound =
-        clonable.type;
-    // class Foo extends Clonable<Foo>
+    // class Cloneable<T extends Cloneable<T>>
+    ClassElementImpl cloneable =
+        ElementFactory.classElement('Cloneable', objectType, ['T']);
+    (cloneable.typeParameters[0] as TypeParameterElementImpl).bound =
+        cloneable.type;
+    // class Foo extends Cloneable<Foo>
     ClassElementImpl foo = ElementFactory.classElement('Foo', null);
-    foo.supertype = clonable.type.instantiate([foo.type]);
+    foo.supertype = cloneable.type.instantiate([foo.type]);
 
-    // <S extends Clonable<S>>
+    // <S extends Cloneable<S>>
     var s = TypeBuilder.variable('S');
     (s.element as TypeParameterElementImpl).bound =
-        clonable.type.instantiate([s]);
+        cloneable.type.instantiate([s]);
     // (S, S) -> S
     var clone = TypeBuilder.function(types: [s], required: [s, s], result: s);
     expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
@@ -2399,12 +2397,11 @@
 class NonNullableSubtypingTest extends SubtypingTestBase {
   @override
   void setUp() {
-    typeProvider = AnalysisContextFactory.contextWithCoreAndOptions(
-            new AnalysisOptionsImpl()
-              ..contextFeatures = FeatureSet.forTesting(
-                  additionalFeatures: [Feature.non_nullable]),
-            resourceProvider: new MemoryResourceProvider())
-        .typeProvider;
+    typeProvider = TestAnalysisContext(
+      featureSet: FeatureSet.forTesting(
+        additionalFeatures: [Feature.non_nullable],
+      ),
+    ).typeProvider;
 
     // TypeSystem should use the context type provider.
     typeSystem = new Dart2TypeSystem(typeProvider);
@@ -2413,7 +2410,11 @@
     LibraryElement asyncLibrary = typeProvider.streamType.element.library;
 
     // Get a non-nullable type provider for convience during the test.
-    typeProvider = new NonNullableTypeProvider(coreLibrary, asyncLibrary);
+    typeProvider = TypeProviderImpl(
+      coreLibrary,
+      asyncLibrary,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
   }
 
   void test_dynamicType() {
@@ -2954,10 +2955,9 @@
   DartType get voidType => VoidTypeImpl.instance;
 
   void setUp() {
-    typeProvider = AnalysisContextFactory.contextWithCore(
-            resourceProvider: new MemoryResourceProvider())
-        .typeProvider;
-    typeSystem = new Dart2TypeSystem(typeProvider);
+    var analysisContext = TestAnalysisContext();
+    typeProvider = analysisContext.typeProvider;
+    typeSystem = analysisContext.typeSystem;
   }
 
   void _checkEquivalent(DartType type1, DartType type2) {
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
deleted file mode 100644
index a689ff0..0000000
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ /dev/null
@@ -1,1333 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_collection.dart';
-import 'package:analyzer/src/source/package_map_resolver.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/model.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../../generated/test_support.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(AnalysisCacheTest);
-    defineReflectiveTests(CacheEntryTest);
-    defineReflectiveTests(CacheFlushManagerTest);
-    defineReflectiveTests(SdkCachePartitionTest);
-    defineReflectiveTests(UniversalCachePartitionTest);
-    defineReflectiveTests(ResultDataTest);
-  });
-}
-
-AnalysisCache createCache({AnalysisContext context}) {
-  CachePartition partition = new UniversalCachePartition(context);
-  return new AnalysisCache(<CachePartition>[partition]);
-}
-
-class AbstractCacheTest {
-  _InternalAnalysisContextMock context;
-  AnalysisCache cache;
-
-  void setUp() {
-    context = new _InternalAnalysisContextMock();
-    context.prioritySources = [];
-    cache = createCache(context: context);
-    context.analysisCache = cache;
-  }
-}
-
-@reflectiveTest
-class AnalysisCacheTest extends AbstractCacheTest {
-  void test_creation() {
-    expect(cache, isNotNull);
-  }
-
-  test_flush() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<String> resultA = new ResultDescriptor<String>('A', null);
-    ResultDescriptor<String> resultB = new ResultDescriptor<String>('B', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // put values
-    entry.setValue(resultA, 'a', const <TargetedResult>[]);
-    entry.setValue(resultB, 'b', const <TargetedResult>[]);
-    expect(cache.getState(target, resultA), CacheState.VALID);
-    expect(cache.getState(target, resultB), CacheState.VALID);
-    expect(cache.getValue(target, resultA), 'a');
-    expect(cache.getValue(target, resultB), 'b');
-    // flush A
-    cache.flush((target, result) => result == resultA);
-    expect(cache.getState(target, resultA), CacheState.FLUSHED);
-    expect(cache.getState(target, resultB), CacheState.VALID);
-    expect(cache.getValue(target, resultA), isNull);
-    expect(cache.getValue(target, resultB), 'b');
-  }
-
-  void test_get() {
-    AnalysisTarget target = new TestSource();
-    expect(cache.get(target), isNull);
-  }
-
-  void test_getContextFor() {
-    AnalysisTarget target = new TestSource();
-    expect(cache.getContextFor(target), context);
-  }
-
-  void test_getSourcesWithFullName() {
-    String filePath = '/foo/lib/file.dart';
-    // no sources
-    expect(cache.getSourcesWithFullName(filePath), isEmpty);
-    // add source1
-    TestSourceWithUri source1 =
-        new TestSourceWithUri(filePath, Uri.parse('file://$filePath'));
-    cache.put(new CacheEntry(source1));
-    expect(cache.getSourcesWithFullName(filePath), unorderedEquals([source1]));
-    // add source2
-    TestSourceWithUri source2 =
-        new TestSourceWithUri(filePath, Uri.parse('package:foo/file.dart'));
-    cache.put(new CacheEntry(source2));
-    expect(cache.getSourcesWithFullName(filePath),
-        unorderedEquals([source1, source2]));
-    // remove source1
-    cache.remove(source1);
-    expect(cache.getSourcesWithFullName(filePath), unorderedEquals([source2]));
-    // remove source2
-    cache.remove(source2);
-    expect(cache.getSourcesWithFullName(filePath), isEmpty);
-    // ignored
-    cache.remove(source1);
-    cache.remove(source2);
-    expect(cache.getSourcesWithFullName(filePath), isEmpty);
-  }
-
-  void test_getState_hasEntry_flushed() {
-    ResultDescriptor result = new ResultDescriptor('result', -1);
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setState(result, CacheState.FLUSHED);
-    expect(cache.getState(target, result), CacheState.FLUSHED);
-  }
-
-  void test_getState_hasEntry_valid() {
-    ResultDescriptor<String> result =
-        new ResultDescriptor<String>('result', null);
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, '', []);
-    expect(cache.getState(target, result), CacheState.VALID);
-  }
-
-  void test_getState_noEntry() {
-    ResultDescriptor result = new ResultDescriptor('result', -1);
-    AnalysisTarget target = new TestSource();
-    expect(cache.getState(target, result), CacheState.INVALID);
-  }
-
-  void test_getValue_hasEntry_valid() {
-    ResultDescriptor<int> result = new ResultDescriptor<int>('result', -1);
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, 111, []);
-    expect(cache.getValue(target, result), 111);
-  }
-
-  void test_getValue_noEntry() {
-    ResultDescriptor result = new ResultDescriptor('result', -1);
-    AnalysisTarget target = new TestSource();
-    expect(cache.getValue(target, result), -1);
-  }
-
-  void test_iterator() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
-    expect(iterator.moveNext(), isTrue);
-    expect(iterator.key, same(target));
-    expect(iterator.value, same(entry));
-    expect(iterator.moveNext(), isFalse);
-  }
-
-  void test_put() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    expect(cache.get(target), isNull);
-    cache.put(entry);
-    expect(cache.get(target), entry);
-  }
-
-  void test_remove() {
-    AnalysisTarget target1 = new TestSource('/a.dart');
-    AnalysisTarget target2 = new TestSource('/b.dart');
-    AnalysisTarget target3 = new TestSource('/c.dart');
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    CacheEntry entry3 = new CacheEntry(target3);
-    cache.put(entry1);
-    cache.put(entry2);
-    cache.put(entry3);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    // set results, all of them are VALID
-    entry1.setValue(result1, 111, const <TargetedResult>[]);
-    entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
-    entry3.setValue(result3, 333, []);
-    expect(entry1.getState(result1), CacheState.VALID);
-    expect(entry2.getState(result2), CacheState.VALID);
-    expect(entry3.getState(result3), CacheState.VALID);
-    expect(entry1.getValue(result1), 111);
-    expect(entry2.getValue(result2), 222);
-    expect(entry3.getValue(result3), 333);
-    // remove entry1, invalidate result2 and remove empty entry2
-    expect(cache.remove(target1), entry1);
-    expect(cache.get(target1), isNull);
-    expect(cache.get(target2), isNull);
-    expect(cache.get(target3), entry3);
-    expect(entry3.getState(result3), CacheState.VALID);
-  }
-
-  void test_remove_invalidateResults_sameTarget() {
-    AnalysisTarget target = new TestSource('/a.dart');
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    // set results, all of them are VALID
-    entry.setValue(result1, 111, const <TargetedResult>[]);
-    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getValue(result1), 111);
-    expect(entry.getValue(result2), 222);
-    // remove target, invalidate result2
-    expect(cache.remove(target), entry);
-    expect(cache.get(target), isNull);
-    expect(entry.getState(result2), CacheState.INVALID);
-  }
-
-  void test_size() {
-    int size = 4;
-    for (int i = 0; i < size; i++) {
-      AnalysisTarget target = new TestSource("/test$i.dart");
-      cache.put(new CacheEntry(target));
-    }
-    expect(cache.size(), size);
-  }
-
-  void test_sources() {
-    AnalysisTarget source1 = new TestSource('1.dart');
-    AnalysisTarget source2 = new TestSource('2.dart');
-    AnalysisTarget target1 = new _TestAnalysisTarget();
-    // no entries
-    expect(cache.sources, isEmpty);
-    // add source1
-    cache.put(new CacheEntry(source1));
-    expect(cache.sources, unorderedEquals([source1]));
-    // add target1
-    cache.put(new CacheEntry(target1));
-    expect(cache.sources, unorderedEquals([source1]));
-    // add source2
-    cache.put(new CacheEntry(source2));
-    expect(cache.sources, unorderedEquals([source1, source2]));
-    // remove source1
-    cache.remove(source1);
-    expect(cache.sources, unorderedEquals([source2]));
-    // remove source2
-    cache.remove(source2);
-    expect(cache.sources, isEmpty);
-  }
-}
-
-@reflectiveTest
-class CacheEntryTest extends AbstractCacheTest {
-  test_dispose() {
-    ResultDescriptor<int> descriptor1 =
-        new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> descriptor2 =
-        new ResultDescriptor<int>('result2', -2);
-    AnalysisTarget target1 = new TestSource('1.dart');
-    AnalysisTarget target2 = new TestSource('2.dart');
-    TargetedResult result1 = new TargetedResult(target1, descriptor1);
-    TargetedResult result2 = new TargetedResult(target2, descriptor2);
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    cache.put(entry1);
-    cache.put(entry2);
-    entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
-    entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
-    // target2 is listed as dependent in target1
-    expect(
-        entry1.getResultData(descriptor1).dependentResults, contains(result2));
-    // dispose entry2, result2 is removed from result1
-    entry2.dispose();
-    expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
-  }
-
-  test_explicitlyAdded() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    expect(entry.explicitlyAdded, false);
-    entry.explicitlyAdded = true;
-    expect(entry.explicitlyAdded, true);
-  }
-
-  test_fixExceptionState_error_exception() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CaughtException exception = new CaughtException(null, null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setErrorState(exception, <ResultDescriptor>[result]);
-    entry.fixExceptionState();
-    expect(entry.getState(result), CacheState.ERROR);
-    expect(entry.exception, exception);
-  }
-
-  test_fixExceptionState_noError_exception() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // set one result to ERROR
-    CaughtException exception = new CaughtException(null, null);
-    entry.setErrorState(exception, <ResultDescriptor>[result]);
-    // set the same result to VALID
-    entry.setValue(result, 1, const <TargetedResult>[]);
-    // fix the exception state
-    entry.fixExceptionState();
-    expect(entry.exception, isNull);
-  }
-
-  test_fixExceptionState_noError_noException() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    entry.fixExceptionState();
-    expect(entry.getState(result), CacheState.INVALID);
-    expect(entry.exception, isNull);
-  }
-
-  test_flush() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<String> resultA = new ResultDescriptor<String>('A', null);
-    ResultDescriptor<String> resultB = new ResultDescriptor<String>('B', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // put values
-    entry.setValue(resultA, 'a', const <TargetedResult>[]);
-    entry.setValue(resultB, 'b', const <TargetedResult>[]);
-    expect(entry.getState(resultA), CacheState.VALID);
-    expect(entry.getState(resultB), CacheState.VALID);
-    expect(entry.getValue(resultA), 'a');
-    expect(entry.getValue(resultB), 'b');
-    // flush A
-    entry.flush((target, result) => result == resultA);
-    expect(entry.getState(resultA), CacheState.FLUSHED);
-    expect(entry.getState(resultB), CacheState.VALID);
-    expect(entry.getValue(resultA), isNull);
-    expect(entry.getValue(resultB), 'b');
-  }
-
-  test_getState() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    expect(entry.getState(result), CacheState.INVALID);
-  }
-
-  test_getValue_default() {
-    AnalysisTarget target = new TestSource();
-    String defaultValue = 'value';
-    ResultDescriptor result = new ResultDescriptor('test', defaultValue);
-    CacheEntry entry = new CacheEntry(target);
-    expect(entry.getValue(result), defaultValue);
-  }
-
-  test_getValue_flushResults() {
-    ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
-    ResultDescriptor<int> descriptor1 = new ResultDescriptor<int>(
-        'result1', null,
-        cachingPolicy: cachingPolicy);
-    ResultDescriptor<int> descriptor2 = new ResultDescriptor<int>(
-        'result2', null,
-        cachingPolicy: cachingPolicy);
-    ResultDescriptor<int> descriptor3 = new ResultDescriptor<int>(
-        'result3', null,
-        cachingPolicy: cachingPolicy);
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    {
-      entry.setValue(descriptor1, 1, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.VALID);
-    }
-    {
-      entry.setValue(descriptor2, 2, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.VALID);
-      expect(entry.getState(descriptor2), CacheState.VALID);
-    }
-    // get descriptor1, so that descriptor2 will be flushed
-    entry.getValue(descriptor1);
-    {
-      entry.setValue(descriptor3, 3, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.VALID);
-      expect(entry.getState(descriptor2), CacheState.FLUSHED);
-      expect(entry.getState(descriptor3), CacheState.VALID);
-    }
-  }
-
-  test_hasErrorState_false() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    expect(entry.hasErrorState(), false);
-  }
-
-  test_hasErrorState_true() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CaughtException exception = new CaughtException(null, null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setErrorState(exception, <ResultDescriptor>[result]);
-    expect(entry.hasErrorState(), true);
-  }
-
-  test_invalidateAllInformation() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<String> result =
-        new ResultDescriptor<String>('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, 'value', const <TargetedResult>[]);
-    entry.invalidateAllInformation();
-    expect(entry.getState(result), CacheState.INVALID);
-    expect(entry.getValue(result), isNull);
-  }
-
-  test_setErrorState() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('res1', 1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('res2', 2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('res3', 3);
-    // prepare some good state
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result1, 10, const <TargetedResult>[]);
-    entry.setValue(result2, 20, const <TargetedResult>[]);
-    entry.setValue(result3, 30, const <TargetedResult>[]);
-    // set error state
-    CaughtException exception = new CaughtException(null, null);
-    entry.setErrorState(exception, <ResultDescriptor>[result1, result2]);
-    // verify
-    expect(entry.exception, exception);
-    expect(entry.getState(result1), CacheState.ERROR);
-    expect(entry.getState(result2), CacheState.ERROR);
-    expect(entry.getState(result3), CacheState.VALID);
-    expect(entry.getValue(result1), 1);
-    expect(entry.getValue(result2), 2);
-    expect(entry.getValue(result3), 30);
-  }
-
-  test_setErrorState_invalidateDependent() {
-    AnalysisTarget target1 = new TestSource('/a.dart');
-    AnalysisTarget target2 = new TestSource('/b.dart');
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    cache.put(entry1);
-    cache.put(entry2);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    ResultDescriptor<int> result4 = new ResultDescriptor<int>('result4', -4);
-    // set results, all of them are VALID
-    entry1.setValue(result1, 111, const <TargetedResult>[]);
-    entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
-    entry2.setValue(result3, 333, [new TargetedResult(target2, result2)]);
-    entry2.setValue(result4, 444, []);
-    expect(entry1.getState(result1), CacheState.VALID);
-    expect(entry2.getState(result2), CacheState.VALID);
-    expect(entry2.getState(result3), CacheState.VALID);
-    expect(entry2.getState(result4), CacheState.VALID);
-    expect(entry1.getValue(result1), 111);
-    expect(entry2.getValue(result2), 222);
-    expect(entry2.getValue(result3), 333);
-    expect(entry2.getValue(result4), 444);
-    // set error state
-    CaughtException exception = new CaughtException(null, null);
-    entry1.setErrorState(exception, <ResultDescriptor>[result1]);
-    // result2 and result3 are invalidated, result4 is intact
-    expect(entry1.getState(result1), CacheState.ERROR);
-    expect(entry2.getState(result2), CacheState.ERROR);
-    expect(entry2.getState(result3), CacheState.ERROR);
-    expect(entry2.getState(result4), CacheState.VALID);
-    expect(entry1.getValue(result1), -1);
-    expect(entry2.getValue(result2), -2);
-    expect(entry2.getValue(result3), -3);
-    expect(entry2.getValue(result4), 444);
-    expect(entry1.exception, exception);
-    expect(entry2.exception, exception);
-  }
-
-  test_setErrorState_noDescriptors() {
-    AnalysisTarget target = new TestSource();
-    CaughtException exception = new CaughtException(null, null);
-    CacheEntry entry = new CacheEntry(target);
-    expect(() {
-      entry.setErrorState(exception, <ResultDescriptor>[]);
-    }, throwsArgumentError);
-  }
-
-  test_setErrorState_noException() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    expect(() {
-      entry.setErrorState(null, <ResultDescriptor>[result]);
-    }, throwsArgumentError);
-  }
-
-  test_setErrorState_nullDescriptors() {
-    AnalysisTarget target = new TestSource();
-    CaughtException exception = new CaughtException(null, null);
-    CacheEntry entry = new CacheEntry(target);
-    expect(() {
-      entry.setErrorState(exception, null);
-    }, throwsArgumentError);
-  }
-
-  test_setState_error() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, 42, const <TargetedResult>[]);
-    // an invalid state change
-    expect(() {
-      entry.setState(result, CacheState.ERROR);
-    }, throwsArgumentError);
-    // no changes
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), 42);
-  }
-
-  test_setState_flushed() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // set VALID
-    entry.setValue(result, 10, const <TargetedResult>[]);
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), 10);
-    // set FLUSHED
-    entry.setState(result, CacheState.FLUSHED);
-    expect(entry.getState(result), CacheState.FLUSHED);
-    expect(entry.getValue(result), 1);
-  }
-
-  test_setState_inProcess() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // set VALID
-    entry.setValue(result, 10, const <TargetedResult>[]);
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), 10);
-    // set IN_PROCESS
-    entry.setState(result, CacheState.IN_PROCESS);
-    expect(entry.getState(result), CacheState.IN_PROCESS);
-    expect(entry.getValue(result), 10);
-  }
-
-  test_setState_invalid() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    // set VALID
-    entry.setValue(result, 10, const <TargetedResult>[]);
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), 10);
-    // listen, expect "result" invalidation event
-    int numberOfEvents = 0;
-    cache.onResultInvalidated.listen((event) {
-      numberOfEvents++;
-      expect(event.entry, same(entry));
-      expect(event.descriptor, same(result));
-    });
-    // set INVALID
-    entry.setState(result, CacheState.INVALID);
-    expect(entry.getState(result), CacheState.INVALID);
-    expect(entry.getValue(result), 1);
-    expect(numberOfEvents, 1);
-  }
-
-  test_setState_invalid_dependencyCycle() {
-    AnalysisTarget target1 = new TestSource('/a.dart');
-    AnalysisTarget target2 = new TestSource('/b.dart');
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    cache.put(entry1);
-    cache.put(entry2);
-    ResultDescriptor<int> result = new ResultDescriptor<int>('result', -1);
-    // Set each result as VALID with a dependency on on the other.
-    entry1.setValue(result, 100, [new TargetedResult(target2, result)]);
-    entry2.setValue(result, 200, [new TargetedResult(target1, result)]);
-    expect(entry1.getState(result), CacheState.VALID);
-    expect(entry2.getState(result), CacheState.VALID);
-    // Listen, expect entry1.result and entry2.result invalidation events.
-    int numberOfEvents = 0;
-    bool wasEntry1 = false;
-    bool wasEntry2 = false;
-    cache.onResultInvalidated.listen((event) {
-      numberOfEvents++;
-      if (event.entry == entry1) wasEntry1 = true;
-      if (event.entry == entry2) wasEntry2 = true;
-      expect(event.descriptor, same(result));
-    });
-    // Invalidate entry1.result; this should cause entry2 to be also
-    // cleared without going into an infinite regress.
-    entry1.setState(result, CacheState.INVALID);
-    expect(cache.get(target1), isNull);
-    expect(cache.get(target2), isNull);
-    expect(numberOfEvents, 2);
-    expect(wasEntry1, isTrue);
-    expect(wasEntry2, isTrue);
-  }
-
-  test_setState_invalid_invalidateDependent() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    ResultDescriptor<int> result4 = new ResultDescriptor<int>('result4', -4);
-    // set results, all of them are VALID
-    entry.setValue(result1, 111, const <TargetedResult>[]);
-    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
-    entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
-    entry.setValue(result4, 444, []);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getState(result3), CacheState.VALID);
-    expect(entry.getState(result4), CacheState.VALID);
-    expect(entry.getValue(result1), 111);
-    expect(entry.getValue(result2), 222);
-    expect(entry.getValue(result3), 333);
-    expect(entry.getValue(result4), 444);
-    // invalidate result1, invalidates result2 and result3, result4 is intact
-    entry.setState(result1, CacheState.INVALID);
-    expect(entry.getState(result1), CacheState.INVALID);
-    expect(entry.getState(result2), CacheState.INVALID);
-    expect(entry.getState(result3), CacheState.INVALID);
-    expect(entry.getState(result4), CacheState.VALID);
-    expect(entry.getValue(result1), -1);
-    expect(entry.getValue(result2), -2);
-    expect(entry.getValue(result3), -3);
-    expect(entry.getValue(result4), 444);
-    // result4 is still valid, so the entry is still in the cache
-    expect(cache.get(target), entry);
-  }
-
-  test_setState_invalid_keepEmpty_ifExplicitlyAdded() {
-    AnalysisTarget target = new TestSource('/a.dart');
-    CacheEntry entry = new CacheEntry(target);
-    entry.explicitlyAdded = true;
-    cache.put(entry);
-    ResultDescriptor<int> result = new ResultDescriptor<int>('result1', -1);
-    // set results, all of them are VALID
-    entry.setValue(result, 111, const <TargetedResult>[]);
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), 111);
-    // invalidate result, keep entry
-    entry.setState(result, CacheState.INVALID);
-    expect(cache.get(target), isNotNull);
-  }
-
-  test_setState_invalid_removeEmptyEntry() {
-    AnalysisTarget target1 = new TestSource('/a.dart');
-    AnalysisTarget target2 = new TestSource('/b.dart');
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    cache.put(entry1);
-    cache.put(entry2);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    // set results, all of them are VALID
-    entry1.setValue(result1, 111, const <TargetedResult>[]);
-    entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
-    entry2.setValue(result3, 333, [new TargetedResult(target2, result2)]);
-    expect(entry1.getState(result1), CacheState.VALID);
-    expect(entry2.getState(result2), CacheState.VALID);
-    expect(entry2.getState(result3), CacheState.VALID);
-    expect(entry1.getValue(result1), 111);
-    expect(entry2.getValue(result2), 222);
-    expect(entry2.getValue(result3), 333);
-    // invalidate result1, remove entry1 & entry2
-    entry1.setState(result1, CacheState.INVALID);
-    expect(cache.get(target1), isNull);
-    expect(cache.get(target2), isNull);
-  }
-
-  test_setState_invalid_withDelta_keepDependency() {
-    Source target = new TestSource('/test.dart');
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    // set results, all of them are VALID
-    entry.setValue(result1, 111, const <TargetedResult>[]);
-    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
-    entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getState(result3), CacheState.VALID);
-    // result2 depends on result1
-    expect(entry.getResultData(result1).dependentResults,
-        unorderedEquals([new TargetedResult(target, result2)]));
-    expect(entry.getResultData(result2).dependedOnResults,
-        unorderedEquals([new TargetedResult(target, result1)]));
-    // record invalidated results
-    Set<TargetedResult> reportedInvalidatedResults = new Set<TargetedResult>();
-    cache.onResultInvalidated.listen((InvalidatedResult invalidatedResult) {
-      reportedInvalidatedResults.add(new TargetedResult(
-          invalidatedResult.entry.target, invalidatedResult.descriptor));
-    });
-    // invalidate result2 with Delta: keep result2, invalidate result3
-    entry.setState(result2, CacheState.INVALID,
-        delta: new _KeepContinueDelta(target, result2));
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getState(result3), CacheState.INVALID);
-    // result2 still depends on result1
-    expect(entry.getResultData(result1).dependentResults,
-        unorderedEquals([new TargetedResult(target, result2)]));
-    expect(entry.getResultData(result2).dependedOnResults,
-        unorderedEquals([new TargetedResult(target, result1)]));
-    // (target, result3) was reported as invalidated
-    // (target, result2) was NOT reported
-    expect(reportedInvalidatedResults,
-        unorderedEquals([new TargetedResult(target, result3)]));
-  }
-
-  test_setState_valid() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor result = new ResultDescriptor('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    expect(() => entry.setState(result, CacheState.VALID), throwsArgumentError);
-  }
-
-  test_setValue() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<String> result =
-        new ResultDescriptor<String>('test', null);
-    String value = 'value';
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, value, const <TargetedResult>[]);
-    expect(entry.getState(result), CacheState.VALID);
-    expect(entry.getValue(result), value);
-  }
-
-  test_setValue_flushResults() {
-    ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
-    ResultDescriptor<int> descriptor1 = new ResultDescriptor<int>(
-        'result1', null,
-        cachingPolicy: cachingPolicy);
-    ResultDescriptor<int> descriptor2 = new ResultDescriptor<int>(
-        'result2', null,
-        cachingPolicy: cachingPolicy);
-    ResultDescriptor<int> descriptor3 = new ResultDescriptor<int>(
-        'result3', null,
-        cachingPolicy: cachingPolicy);
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    {
-      entry.setValue(descriptor1, 1, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.VALID);
-    }
-    {
-      entry.setValue(descriptor2, 2, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.VALID);
-      expect(entry.getState(descriptor2), CacheState.VALID);
-    }
-    {
-      entry.setValue(descriptor3, 3, const <TargetedResult>[]);
-      expect(entry.getState(descriptor1), CacheState.FLUSHED);
-      expect(entry.getState(descriptor2), CacheState.VALID);
-      expect(entry.getState(descriptor3), CacheState.VALID);
-    }
-  }
-
-  test_setValue_flushResults_keepForPrioritySources() {
-    ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
-    ResultDescriptor<int> newResult(String name) =>
-        new ResultDescriptor<int>(name, null, cachingPolicy: cachingPolicy);
-    ResultDescriptor<int> descriptor1 = newResult('result1');
-    ResultDescriptor<int> descriptor2 = newResult('result2');
-    ResultDescriptor<int> descriptor3 = newResult('result3');
-    TestSource source1 = new TestSource('/a.dart');
-    TestSource source2 = new TestSource('/b.dart');
-    TestSource source3 = new TestSource('/c.dart');
-    AnalysisTarget target1 =
-        new _TestAnalysisTarget(librarySource: source1, source: source1);
-    AnalysisTarget target2 =
-        new _TestAnalysisTarget(librarySource: source2, source: source2);
-    AnalysisTarget target3 =
-        new _TestAnalysisTarget(librarySource: source3, source: source3);
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    CacheEntry entry3 = new CacheEntry(target3);
-    cache.put(entry1);
-    cache.put(entry2);
-    cache.put(entry3);
-
-    // Set two results.
-    entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
-    entry2.setValue(descriptor2, 2, const <TargetedResult>[]);
-    expect(entry1.getState(descriptor1), CacheState.VALID);
-    expect(entry2.getState(descriptor2), CacheState.VALID);
-
-    // Make source1 priority, so result2 is flushed instead.
-    context.prioritySources = <Source>[source1];
-    entry3.setValue(descriptor3, 3, const <TargetedResult>[]);
-    expect(entry1.getState(descriptor1), CacheState.VALID);
-    expect(entry2.getState(descriptor2), CacheState.FLUSHED);
-    expect(entry3.getState(descriptor3), CacheState.VALID);
-  }
-
-  test_setValue_keepDependent() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    // set results, all of them are VALID
-    entry.setValue(result1, 111, const <TargetedResult>[]);
-    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getValue(result1), 111);
-    expect(entry.getValue(result2), 222);
-    // set result1; result2 is intact
-    entry.setValue(result1, 1111, const <TargetedResult>[]);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getValue(result1), 1111);
-    expect(entry.getValue(result2), 222);
-  }
-
-  test_setValue_userBeforeProvider_invalidateProvider_alsoUser() {
-    AnalysisTarget target1 = new TestSource('/a.dart');
-    AnalysisTarget target2 = new TestSource('/b.dart');
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    cache.put(entry1);
-    cache.put(entry2);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    // set results, all of them are VALID
-    entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
-    entry1.setValue(result1, 111, const <TargetedResult>[]);
-    expect(entry1.getState(result1), CacheState.VALID);
-    expect(entry2.getState(result2), CacheState.VALID);
-    expect(entry1.getValue(result1), 111);
-    expect(entry2.getValue(result2), 222);
-    // invalidate result1, should invalidate also result2
-    entry1.setState(result1, CacheState.INVALID);
-    expect(entry1.getState(result1), CacheState.INVALID);
-    expect(entry2.getState(result2), CacheState.INVALID);
-  }
-
-  test_setValueIncremental() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
-    ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
-    // set results, all of them are VALID
-    entry.setValue(result1, 111, const <TargetedResult>[]);
-    entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
-    entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getState(result3), CacheState.VALID);
-    expect(entry.getValue(result1), 111);
-    expect(entry.getValue(result2), 222);
-    expect(entry.getValue(result3), 333);
-    // replace result1, keep "dependedOn", invalidate result3
-    entry.setValueIncremental(result2, 2222, true);
-    expect(entry.getState(result1), CacheState.VALID);
-    expect(entry.getState(result2), CacheState.VALID);
-    expect(entry.getState(result3), CacheState.INVALID);
-    expect(entry.getValue(result1), 111);
-    expect(entry.getValue(result2), 2222);
-    expect(entry.getValue(result3), -3);
-    expect(entry.getResultData(result1).dependentResults,
-        unorderedEquals([new TargetedResult(target, result2)]));
-    expect(entry.getResultData(result2).dependedOnResults,
-        unorderedEquals([new TargetedResult(target, result1)]));
-  }
-
-  test_toString_empty() {
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    expect(entry.toString(), isNotNull);
-  }
-
-  test_toString_nonEmpty() {
-    AnalysisTarget target = new TestSource();
-    ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
-    CacheEntry entry = new CacheEntry(target);
-    cache.put(entry);
-    entry.setValue(result, 42, const <TargetedResult>[]);
-    expect(entry.toString(), isNotNull);
-  }
-}
-
-@reflectiveTest
-class CacheFlushManagerTest {
-  CacheFlushManager manager = new CacheFlushManager(
-      new SimpleResultCachingPolicy(15, 3), (AnalysisTarget target) => false);
-
-  test_madeActive() {
-    manager.madeActive();
-    expect(manager.maxSize, 15);
-  }
-
-  test_madeIdle() {
-    manager.madeActive();
-    AnalysisTarget target = new TestSource();
-    // prepare TargetedResult(s)
-    List<TargetedResult> results = <TargetedResult>[];
-    for (int i = 0; i < 15; i++) {
-      ResultDescriptor descriptor = new ResultDescriptor('result$i', null);
-      results.add(new TargetedResult(target, descriptor));
-    }
-    // notify about storing TargetedResult(s)
-    for (TargetedResult result in results) {
-      manager.resultStored(result, null);
-    }
-    expect(manager.recentlyUsed, results);
-    expect(manager.currentSize, 15);
-    // make idle
-    List<TargetedResult> resultsToFlush = manager.madeIdle();
-    expect(manager.maxSize, 3);
-    expect(manager.recentlyUsed, results.skip(15 - 3));
-    expect(resultsToFlush, results.take(15 - 3));
-  }
-
-  test_new() {
-    expect(manager.maxActiveSize, 15);
-    expect(manager.maxIdleSize, 3);
-    expect(manager.maxSize, 15);
-    expect(manager.currentSize, 0);
-    expect(manager.recentlyUsed, isEmpty);
-  }
-
-  test_resultAccessed() {
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
-    AnalysisTarget target = new TestSource();
-    TargetedResult result1 = new TargetedResult(target, descriptor1);
-    TargetedResult result2 = new TargetedResult(target, descriptor2);
-    TargetedResult result3 = new TargetedResult(target, descriptor3);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    manager.resultStored(result3, null);
-    expect(manager.currentSize, 3);
-    expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
-    // access result2
-    manager.resultAccessed(result2);
-    expect(manager.currentSize, 3);
-    expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
-  }
-
-  test_resultAccessed_negativeMaxSize() {
-    manager = new CacheFlushManager(new SimpleResultCachingPolicy(-1, -1),
-        (AnalysisTarget target) => false);
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    AnalysisTarget target = new TestSource();
-    TargetedResult result1 = new TargetedResult(target, descriptor1);
-    TargetedResult result2 = new TargetedResult(target, descriptor2);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    expect(manager.currentSize, 0);
-    expect(manager.recentlyUsed, isEmpty);
-    // access result2
-    manager.resultAccessed(result2);
-    expect(manager.currentSize, 0);
-    expect(manager.recentlyUsed, isEmpty);
-  }
-
-  test_resultAccessed_noSuchResult() {
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
-    AnalysisTarget target = new TestSource();
-    TargetedResult result1 = new TargetedResult(target, descriptor1);
-    TargetedResult result2 = new TargetedResult(target, descriptor2);
-    TargetedResult result3 = new TargetedResult(target, descriptor3);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    expect(manager.currentSize, 2);
-    expect(manager.recentlyUsed, orderedEquals([result1, result2]));
-    // access result3, no-op
-    manager.resultAccessed(result3);
-    expect(manager.currentSize, 2);
-    expect(manager.recentlyUsed, orderedEquals([result1, result2]));
-  }
-
-  test_resultStored() {
-    CacheFlushManager manager = new CacheFlushManager(
-        new SimpleResultCachingPolicy(3, 3), (AnalysisTarget target) => false);
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
-    ResultDescriptor descriptor4 = new ResultDescriptor('result4', null);
-    AnalysisTarget target = new TestSource();
-    TargetedResult result1 = new TargetedResult(target, descriptor1);
-    TargetedResult result2 = new TargetedResult(target, descriptor2);
-    TargetedResult result3 = new TargetedResult(target, descriptor3);
-    TargetedResult result4 = new TargetedResult(target, descriptor4);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    manager.resultStored(result3, null);
-    expect(manager.currentSize, 3);
-    expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
-    // store result2 again
-    {
-      List<TargetedResult> resultsToFlush = manager.resultStored(result2, null);
-      expect(resultsToFlush, isEmpty);
-      expect(manager.currentSize, 3);
-      expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
-    }
-    // store result4
-    {
-      List<TargetedResult> resultsToFlush = manager.resultStored(result4, null);
-      expect(resultsToFlush, [result1]);
-      expect(manager.currentSize, 3);
-      expect(manager.recentlyUsed, orderedEquals([result3, result2, result4]));
-      expect(manager.resultSizeMap, {result3: 1, result2: 1, result4: 1});
-    }
-  }
-
-  test_resultStored_negativeMaxSize() {
-    manager = new CacheFlushManager(new SimpleResultCachingPolicy(-1, -1),
-        (AnalysisTarget target) => false);
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    AnalysisTarget target = new TestSource();
-    TargetedResult result1 = new TargetedResult(target, descriptor1);
-    TargetedResult result2 = new TargetedResult(target, descriptor2);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    expect(manager.currentSize, 0);
-    expect(manager.recentlyUsed, isEmpty);
-  }
-
-  test_targetRemoved() {
-    ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
-    ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
-    ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
-    AnalysisTarget target1 = new TestSource('a.dart');
-    AnalysisTarget target2 = new TestSource('b.dart');
-    TargetedResult result1 = new TargetedResult(target1, descriptor1);
-    TargetedResult result2 = new TargetedResult(target2, descriptor2);
-    TargetedResult result3 = new TargetedResult(target1, descriptor3);
-    manager.resultStored(result1, null);
-    manager.resultStored(result2, null);
-    manager.resultStored(result3, null);
-    expect(manager.currentSize, 3);
-    expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
-    expect(manager.resultSizeMap, {result1: 1, result2: 1, result3: 1});
-    // remove target1
-    {
-      manager.targetRemoved(target1);
-      expect(manager.currentSize, 1);
-      expect(manager.recentlyUsed, orderedEquals([result2]));
-      expect(manager.resultSizeMap, {result2: 1});
-    }
-    // remove target2
-    {
-      manager.targetRemoved(target2);
-      expect(manager.currentSize, 0);
-      expect(manager.recentlyUsed, isEmpty);
-      expect(manager.resultSizeMap, isEmpty);
-    }
-  }
-}
-
-abstract class CachePartitionTest extends EngineTestCase {
-  CachePartition createPartition();
-
-  void test_creation() {
-    expect(createPartition(), isNotNull);
-  }
-
-  void test_dispose() {
-    CachePartition partition = createPartition();
-    Source source1 = new TestSource('/1.dart');
-    Source source2 = new TestSource('/2.dart');
-    CacheEntry entry1 = new CacheEntry(source1);
-    CacheEntry entry2 = new CacheEntry(source2);
-    // add two sources
-    partition.put(entry1);
-    partition.put(entry2);
-    expect(partition.entryMap, hasLength(2));
-    expect(partition.pathToSource, hasLength(2));
-    expect(partition.sources, unorderedEquals([source1, source2]));
-    // dispose, no sources
-    partition.dispose();
-    expect(partition.entryMap, isEmpty);
-    expect(partition.pathToSource, isEmpty);
-    expect(partition.sources, isEmpty);
-  }
-
-  void test_entrySet() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    partition.put(entry);
-    Map<AnalysisTarget, CacheEntry> entryMap = partition.entryMap;
-    expect(entryMap, hasLength(1));
-    AnalysisTarget entryKey = entryMap.keys.first;
-    expect(entryKey, target);
-    expect(entryMap[entryKey], entry);
-  }
-
-  void test_get() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    expect(partition.get(target), isNull);
-  }
-
-  void test_put_alreadyInPartition() {
-    CachePartition partition1 = createPartition();
-    CachePartition partition2 = createPartition();
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    partition1.put(entry);
-    expect(() => partition2.put(entry), throwsStateError);
-  }
-
-  void test_put_noFlush() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    partition.put(entry);
-    expect(partition.get(target), entry);
-  }
-
-  void test_remove_absent() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    expect(partition.get(target), isNull);
-    expect(partition.remove(target), isNull);
-    expect(partition.get(target), isNull);
-  }
-
-  void test_remove_present() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    CacheEntry entry = new CacheEntry(target);
-    partition.put(entry);
-    expect(partition.get(target), entry);
-    expect(partition.remove(target), entry);
-    expect(partition.get(target), isNull);
-  }
-}
-
-@reflectiveTest
-class PackageCachePartitionTest extends CachePartitionTest
-    with ResourceProviderMixin {
-  Folder rootFolder;
-
-  CachePartition createPartition() {
-    rootFolder = newFolder('/package/root');
-    return new PackageCachePartition(null, rootFolder);
-  }
-
-  void test_contains_false() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    expect(partition.isResponsibleFor(target), isFalse);
-  }
-
-  void test_contains_true() {
-    SdkCachePartition partition = new SdkCachePartition(null);
-    SourceFactory factory = new SourceFactory([
-      new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
-        'root': <Folder>[rootFolder]
-      })
-    ]);
-    AnalysisTarget target = factory.forUri("package:root/root.dart");
-    expect(partition.isResponsibleFor(target), isTrue);
-  }
-}
-
-@reflectiveTest
-class ResultDataTest extends EngineTestCase {
-  test_creation() {
-    String value = 'value';
-    ResultData data = new ResultData(new ResultDescriptor('test', value));
-    expect(data, isNotNull);
-    expect(data.state, CacheState.INVALID);
-    expect(data.value, value);
-  }
-
-  test_flush() {
-    ResultDescriptor result = new ResultDescriptor('test', -1);
-    ResultData data = new ResultData(result);
-    data.state = CacheState.VALID;
-    data.value = 123;
-    data.flush();
-    expect(data.state, CacheState.FLUSHED);
-    expect(data.value, -1);
-  }
-}
-
-@reflectiveTest
-class SdkCachePartitionTest extends CachePartitionTest {
-  CachePartition createPartition() {
-    return new SdkCachePartition(null);
-  }
-
-  void test_contains_false() {
-    CachePartition partition = createPartition();
-    AnalysisTarget target = new TestSource();
-    expect(partition.isResponsibleFor(target), isFalse);
-  }
-
-  void test_contains_true() {
-    SdkCachePartition partition = new SdkCachePartition(null);
-    ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
-    FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
-        FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
-    SourceFactory factory = new SourceFactory([new DartUriResolver(sdk)]);
-    AnalysisTarget target = factory.forUri("dart:core");
-    expect(partition.isResponsibleFor(target), isTrue);
-  }
-}
-
-@reflectiveTest
-class UniversalCachePartitionTest extends CachePartitionTest {
-  CachePartition createPartition() {
-    return new UniversalCachePartition(null);
-  }
-
-  void test_contains() {
-    UniversalCachePartition partition = new UniversalCachePartition(null);
-    TestSource source = new TestSource();
-    expect(partition.isResponsibleFor(source), isTrue);
-  }
-
-  test_dispose() {
-    _InternalAnalysisContextMock context = new _InternalAnalysisContextMock();
-    CachePartition partition1 = new UniversalCachePartition(context);
-    CachePartition partition2 = new UniversalCachePartition(context);
-    AnalysisCache cache = new AnalysisCache([partition1, partition2]);
-    context.analysisCache = cache;
-    // configure
-    // prepare entries
-    ResultDescriptor<int> descriptor1 =
-        new ResultDescriptor<int>('result1', -1);
-    ResultDescriptor<int> descriptor2 =
-        new ResultDescriptor<int>('result2', -2);
-    AnalysisTarget target1 = new TestSource('1.dart');
-    AnalysisTarget target2 = new TestSource('2.dart');
-    TargetedResult result1 = new TargetedResult(target1, descriptor1);
-    TargetedResult result2 = new TargetedResult(target2, descriptor2);
-    CacheEntry entry1 = new CacheEntry(target1);
-    CacheEntry entry2 = new CacheEntry(target2);
-    partition1.put(entry1);
-    partition2.put(entry2);
-    entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
-    entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
-    // target2 is listed as dependent in target1
-    expect(
-        entry1.getResultData(descriptor1).dependentResults, contains(result2));
-    // dispose
-    partition2.dispose();
-    expect(partition1.get(target1), same(entry1));
-    expect(partition2.get(target2), isNull);
-    // result2 is removed from result1
-    expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
-  }
-}
-
-class _InternalAnalysisContextMock implements InternalAnalysisContext {
-  @override
-  final AnalysisOptions analysisOptions = new AnalysisOptionsImpl();
-
-  @override
-  AnalysisCache analysisCache;
-
-  @override
-  List<Source> prioritySources = <Source>[];
-
-  @override
-  noSuchMethod(Invocation invocation) {
-    throw new StateError('Unexpected invocation of ${invocation.memberName}');
-  }
-}
-
-/**
- * Keep the given [keepDescriptor], invalidate all the other results.
- */
-class _KeepContinueDelta implements Delta {
-  final Source source;
-  final ResultDescriptor keepDescriptor;
-
-  _KeepContinueDelta(this.source, this.keepDescriptor);
-
-  @override
-  bool get shouldGatherChanges => false;
-
-  @override
-  bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
-      ResultDescriptor descriptor, Object value) {
-    return false;
-  }
-
-  @override
-  void gatherEnd() {}
-
-  @override
-  DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
-      ResultDescriptor descriptor, Object value) {
-    if (descriptor == keepDescriptor) {
-      return DeltaResult.KEEP_CONTINUE;
-    }
-    return DeltaResult.INVALIDATE;
-  }
-}
-
-class _TestAnalysisTarget implements AnalysisTarget {
-  final Source librarySource;
-  final Source source;
-  _TestAnalysisTarget({this.librarySource, this.source});
-}
diff --git a/pkg/analyzer/test/src/context/test_all.dart b/pkg/analyzer/test/src/context/test_all.dart
index 5f5e2d0..ffe28aa 100644
--- a/pkg/analyzer/test/src/context/test_all.dart
+++ b/pkg/analyzer/test/src/context/test_all.dart
@@ -5,14 +5,12 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'builder_test.dart' as builder_test;
-import 'cache_test.dart' as cache_test;
 import 'source_test.dart' as source_test;
 
 /// Utility for manually running all tests.
 main() {
   defineReflectiveSuite(() {
     builder_test.main();
-    cache_test.main();
     source_test.main();
   }, name: 'context');
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index dcc2fad..dc8f58b 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
@@ -711,15 +710,8 @@
   }
 }
 
-/// TODO(paulberry): migrate this test away from the task model.
-/// See dartbug.com/35734.
 @reflectiveTest
 class AnalysisDriverTest extends BaseAnalysisDriverTest {
-  void configurePreviewDart2() {
-    driver.configure(
-        analysisOptions: new AnalysisOptionsImpl.from(driver.analysisOptions));
-  }
-
   test_addedFiles() async {
     var a = convertPath('/test/lib/a.dart');
     var b = convertPath('/test/lib/b.dart');
@@ -1278,8 +1270,6 @@
   }
 
   test_const_implicitCreation() async {
-    configurePreviewDart2();
-
     var a = convertPath('/test/bin/a.dart');
     var b = convertPath('/test/bin/b.dart');
     newFile(a, content: r'''
@@ -1304,8 +1294,6 @@
   }
 
   test_const_implicitCreation_rewrite() async {
-    configurePreviewDart2();
-
     var a = convertPath('/test/bin/a.dart');
     var b = convertPath('/test/bin/b.dart');
     newFile(a, content: r'''
@@ -1954,10 +1942,7 @@
     ResolvedUnitResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
     // Has only exports for valid URIs.
-    List<ExportElement> imports = resolutionMap
-        .elementDeclaredByCompilationUnit(result.unit)
-        .library
-        .exports;
+    List<ExportElement> imports = result.libraryElement.exports;
     expect(imports.map((import) {
       return import.exportedLibrary?.source?.uri?.toString();
     }), ['dart:async', null, 'dart:math']);
@@ -1974,10 +1959,7 @@
     ResolvedUnitResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
     // Has only imports for valid URIs.
-    List<ImportElement> imports = resolutionMap
-        .elementDeclaredByCompilationUnit(result.unit)
-        .library
-        .imports;
+    List<ImportElement> imports = result.libraryElement.imports;
     expect(imports.map((import) {
       return import.importedLibrary?.source?.uri?.toString();
     }), ['dart:async', null, 'dart:math', 'dart:core']);
@@ -3452,9 +3434,8 @@
 
   String _getClassFieldType(
       CompilationUnit unit, String className, String fieldName) {
-    return resolutionMap
-        .elementDeclaredByVariableDeclaration(
-            _getClassField(unit, className, fieldName))
+    return _getClassField(unit, className, fieldName)
+        .declaredElement
         .type
         .toString();
   }
@@ -3474,9 +3455,8 @@
 
   String _getClassMethodReturnType(
       CompilationUnit unit, String className, String fieldName) {
-    return resolutionMap
-        .elementDeclaredByMethodDeclaration(
-            _getClassMethod(unit, className, fieldName))
+    return _getClassMethod(unit, className, fieldName)
+        .declaredElement
         .type
         .returnType
         .toString();
@@ -3506,10 +3486,7 @@
 
   String _getTopLevelVarType(CompilationUnit unit, String name) {
     VariableDeclaration variable = _getTopLevelVar(unit, name);
-    return resolutionMap
-        .elementDeclaredByVariableDeclaration(variable)
-        .type
-        .toString();
+    return variable.declaredElement.type.toString();
   }
 }
 
diff --git a/pkg/analyzer/test/src/dart/analysis/results_test.dart b/pkg/analyzer/test/src/dart/analysis/results_test.dart
index 06a0b47..030194c 100644
--- a/pkg/analyzer/test/src/dart/analysis/results_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/results_test.dart
@@ -2,10 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -14,10 +16,32 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(GetElementDeclarationParsedTest);
+    defineReflectiveTests(GetElementDeclarationParsedWithExtensionMethodsTest);
     defineReflectiveTests(GetElementDeclarationResolvedTest);
+    defineReflectiveTests(
+        GetElementDeclarationResolvedWithExtensionMethodsTest);
   });
 }
 
+mixin ExtensionMethodsMixin implements GetElementDeclarationMixin {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_extension() async {
+    addTestFile(r'''
+extension E on int {}
+''');
+    await resolveTestFile();
+
+    var element = findNode.extensionDeclaration('E').declaredElement;
+    var result = await getElementDeclaration(element);
+    ExtensionDeclaration node = result.node;
+    expect(node.name.name, 'E');
+  }
+}
+
 mixin GetElementDeclarationMixin implements DriverResolutionTest {
   Future<ElementDeclarationResult> getElementDeclaration(Element element);
 
@@ -461,6 +485,10 @@
 }
 
 @reflectiveTest
+class GetElementDeclarationParsedWithExtensionMethodsTest
+    extends GetElementDeclarationParsedTest with ExtensionMethodsMixin {}
+
+@reflectiveTest
 class GetElementDeclarationResolvedTest extends DriverResolutionTest
     with GetElementDeclarationMixin {
   @override
@@ -475,3 +503,7 @@
     return driver.getResolvedLibrary(path);
   }
 }
+
+@reflectiveTest
+class GetElementDeclarationResolvedWithExtensionMethodsTest
+    extends GetElementDeclarationResolvedTest with ExtensionMethodsMixin {}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 8b8b2a0..f74da70 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart' hide Declaration;
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/analysis/search.dart';
 import 'package:analyzer/src/dart/ast/element_locator.dart';
@@ -349,8 +348,7 @@
     ConstructorElement element = _findElementAtString('A() {}');
 
     CompilationUnit otherUnit = (await driver.getResult(other)).unit;
-    Element main =
-        resolutionMap.elementDeclaredByCompilationUnit(otherUnit).functions[0];
+    Element main = otherUnit.declaredElement.functions[0];
     var expected = [
       new ExpectedResult(main, SearchResultKind.REFERENCE,
           otherCode.indexOf('(); // in other'), 0,
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index ee62881..15d7978 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -10,7 +10,6 @@
 import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
-import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
@@ -3332,24 +3331,6 @@
         unorderedEquals(<CompilationUnitElement>[unitLib, unitA, unitB]));
   }
 
-  void test_invalidateLibraryCycles_withHandle() {
-    AnalysisContext context = createAnalysisContext();
-    context.sourceFactory = new SourceFactory([]);
-    LibraryElementImpl library = ElementFactory.library(context, "foo");
-    LibraryElementImpl importedLibrary = ElementFactory.library(context, "bar");
-    ElementLocation location = new ElementLocationImpl.con2('');
-    TestElementResynthesizer resynthesizer =
-        new TestElementResynthesizer(context, {location: importedLibrary});
-    LibraryElement importedLibraryHandle =
-        new LibraryElementHandle(resynthesizer, location);
-    ImportElementImpl import =
-        ElementFactory.importFor(importedLibraryHandle, null);
-    library.imports = <ImportElement>[import];
-    library.libraryCycle; // Force computation of the cycle.
-
-    library.invalidateLibraryCycles();
-  }
-
   void test_setImports() {
     AnalysisContext context = createAnalysisContext();
     LibraryElementImpl library = new LibraryElementImpl.forNode(
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index d3a06ce..e75f914 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -131,6 +132,63 @@
     assertType(right, 'int');
   }
 
+  test_compound_refineType_int_double() async {
+    await assertErrorsInCode(r'''
+main(int i) {
+  i += 1.2;
+  i -= 1.2;
+  i *= 1.2;
+  i %= 1.2;
+}
+''', [
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 21, 3),
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 33, 3),
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 45, 3),
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 57, 3),
+    ]);
+    assertType(findNode.assignment('+='), 'double');
+    assertType(findNode.assignment('-='), 'double');
+    assertType(findNode.assignment('*='), 'double');
+    assertType(findNode.assignment('%='), 'double');
+  }
+
+  test_compound_refineType_int_int() async {
+    await assertNoErrorsInCode(r'''
+main(int i) {
+  i += 1;
+  i -= 1;
+  i *= 1;
+  i ~/= 1;
+  i %= 1;
+}
+''');
+    assertType(findNode.assignment('+='), 'int');
+    assertType(findNode.assignment('-='), 'int');
+    assertType(findNode.assignment('*='), 'int');
+    assertType(findNode.assignment('~/='), 'int');
+    assertType(findNode.assignment('%='), 'int');
+  }
+
+  test_compoundIfNull_differentTypes() async {
+    await assertErrorsInCode(r'''
+main(double a, int b) {
+  a ??= b;
+}
+''', [
+      error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 32, 1),
+    ]);
+    assertType(findNode.assignment('??='), 'num');
+  }
+
+  test_compoundIfNull_sameTypes() async {
+    await assertNoErrorsInCode(r'''
+main(int a) {
+  a ??= 0;
+}
+''');
+    assertType(findNode.assignment('??='), 'int');
+  }
+
   test_in_const_context() async {
     addTestFile('''
 void f(num x, int y) {
diff --git a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
index 73316d2..5cfd48d 100644
--- a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
@@ -382,6 +382,10 @@
     @required String expectedExtendedType,
   }) {
     expect(override.staticElement, expectedElement);
+
+    assertTypeNull(override);
+    assertTypeNull(override.extensionName);
+
     assertElementTypeStrings(
       override.typeArgumentTypes,
       expectedTypeArguments,
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
index a51e157..7c00d1f 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
@@ -15,6 +15,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ExtensionMethodsDeclarationTest);
+    defineReflectiveTests(ExtensionMethodsExtendedTypeTest);
     defineReflectiveTests(ExtensionMethodsExternalReferenceTest);
     defineReflectiveTests(ExtensionMethodsInternalReferenceTest);
   });
@@ -48,6 +49,31 @@
         ])
       ];
 
+  test_constructor() async {
+    await assertErrorsInCode('''
+extension E {
+  E() {}
+}
+''', [
+      error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+      error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
+      error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 1),
+    ]);
+  }
+
+  test_factory() async {
+    await assertErrorsInCode('''
+extension E {
+  factory S() {}
+}
+''', [
+      error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 12, 0),
+      error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
+      error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 7),
+    ]);
+  }
+
   test_fromPlatform() async {
     await assertNoErrorsInCode('''
 import 'dart:test2';
@@ -77,110 +103,6 @@
 ''');
   }
 
-  test_named_generic() async {
-    await assertNoErrorsInCode('''
-class C<T> {}
-extension E<S> on C<S> {}
-''');
-    var extendedType = findNode.typeAnnotation('C<S>');
-    assertElement(extendedType, findElement.class_('C'));
-    assertType(extendedType, 'C<S>');
-  }
-
-  test_named_onDynamic() async {
-    await assertNoErrorsInCode('''
-extension E on dynamic {}
-''');
-    var extendedType = findNode.typeAnnotation('dynamic');
-    assertType(extendedType, 'dynamic');
-  }
-
-  test_named_onEnum() async {
-    await assertNoErrorsInCode('''
-enum A {a, b, c}
-extension E on A {}
-''');
-    var extendedType = findNode.typeAnnotation('A {}');
-    assertElement(extendedType, findElement.enum_('A'));
-    assertType(extendedType, 'A');
-  }
-
-  test_named_onFunctionType() async {
-    try {
-      await assertNoErrorsInCode('''
-extension E on int Function(int) {}
-''');
-      var extendedType = findNode.typeAnnotation('Function');
-      assertType(extendedType, 'int Function(int)');
-      if (!AnalysisDriver.useSummary2) {
-        throw 'Test passed - expected to fail.';
-      }
-    } on String {
-      rethrow;
-    } catch (e) {
-      if (AnalysisDriver.useSummary2) {
-        rethrow;
-      }
-    }
-  }
-
-  test_named_onInterface() async {
-    await assertNoErrorsInCode('''
-class C { }
-extension E on C {}
-''');
-    var extendedType = findNode.typeAnnotation('C {}');
-    assertElement(extendedType, findElement.class_('C'));
-    assertType(extendedType, 'C');
-  }
-
-  test_unnamed_generic() async {
-    await assertNoErrorsInCode('''
-class C<T> {}
-extension<S> on C<S> {}
-''');
-    var extendedType = findNode.typeAnnotation('C<S>');
-    assertElement(extendedType, findElement.class_('C'));
-    assertType(extendedType, 'C<S>');
-  }
-
-  test_unnamed_onDynamic() async {
-    await assertNoErrorsInCode('''
-extension on dynamic {}
-''');
-    var extendedType = findNode.typeAnnotation('dynamic');
-    assertType(extendedType, 'dynamic');
-  }
-
-  test_unnamed_onEnum() async {
-    await assertNoErrorsInCode('''
-enum A {a, b, c}
-extension on A {}
-''');
-    var extendedType = findNode.typeAnnotation('A {}');
-    assertElement(extendedType, findElement.enum_('A'));
-    assertType(extendedType, 'A');
-  }
-
-  @failingTest
-  test_unnamed_onFunctionType() async {
-    await assertNoErrorsInCode('''
-extension on int Function(int) {}
-''');
-    var extendedType = findNode.typeAnnotation('int ');
-    assertType(extendedType, 'int Function(int)');
-  }
-
-  test_unnamed_onInterface() async {
-    await assertNoErrorsInCode('''
-class C { }
-extension on C {}
-''');
-    var extendedType = findNode.typeAnnotation('C {}');
-    assertElement(extendedType, findElement.class_('C'));
-    assertType(extendedType, 'C');
-  }
-
   test_visibility_hidden() async {
     newFile('/test/lib/lib.dart', content: '''
 class C {}
@@ -337,7 +259,6 @@
 ''');
   }
 
-  @failingTest
   test_visibility_withPrefix() async {
     newFile('/test/lib/lib.dart', content: '''
 class C {}
@@ -357,6 +278,129 @@
   }
 }
 
+/// Tests that show that extension declarations support all of the possible
+/// types in the `on` clause.
+@reflectiveTest
+class ExtensionMethodsExtendedTypeTest extends BaseExtensionMethodsTest {
+  test_named_generic() async {
+    await assertNoErrorsInCode('''
+class C<T> {}
+extension E<S> on C<S> {}
+''');
+    var extendedType = findNode.typeAnnotation('C<S>');
+    assertElement(extendedType, findElement.class_('C'));
+    assertType(extendedType, 'C<S>');
+  }
+
+  test_named_onDynamic() async {
+    await assertNoErrorsInCode('''
+extension E on dynamic {}
+''');
+    var extendedType = findNode.typeAnnotation('dynamic');
+    assertType(extendedType, 'dynamic');
+  }
+
+  test_named_onEnum() async {
+    await assertNoErrorsInCode('''
+enum A {a, b, c}
+extension E on A {}
+''');
+    var extendedType = findNode.typeAnnotation('A {}');
+    assertElement(extendedType, findElement.enum_('A'));
+    assertType(extendedType, 'A');
+  }
+
+  test_named_onFunctionType() async {
+    await assertNoErrorsInCode('''
+extension E on int Function(int) {}
+''');
+    var extendedType = findNode.typeAnnotation('Function');
+    assertType(extendedType, 'int Function(int)');
+  }
+
+  test_named_onInterface() async {
+    await assertNoErrorsInCode('''
+class C { }
+extension E on C {}
+''');
+    var extendedType = findNode.typeAnnotation('C {}');
+    assertElement(extendedType, findElement.class_('C'));
+    assertType(extendedType, 'C');
+  }
+
+  test_named_onMixin() async {
+    await assertNoErrorsInCode('''
+mixin M {
+}
+extension E on M {}
+''');
+    var extendedType = findNode.typeAnnotation('M {}');
+    assertElement(extendedType, findElement.mixin('M'));
+    assertType(extendedType, 'M');
+  }
+
+  test_unnamed_generic() async {
+    await assertNoErrorsInCode('''
+class C<T> {}
+extension<S> on C<S> {}
+''');
+    var extendedType = findNode.typeAnnotation('C<S>');
+    assertElement(extendedType, findElement.class_('C'));
+    assertType(extendedType, 'C<S>');
+  }
+
+  test_unnamed_onDynamic() async {
+    await assertNoErrorsInCode('''
+extension on dynamic {}
+''');
+    var extendedType = findNode.typeAnnotation('dynamic');
+    assertType(extendedType, 'dynamic');
+  }
+
+  test_unnamed_onEnum() async {
+    await assertNoErrorsInCode('''
+enum A {a, b, c}
+extension on A {}
+''');
+    var extendedType = findNode.typeAnnotation('A {}');
+    assertElement(extendedType, findElement.enum_('A'));
+    assertType(extendedType, 'A');
+  }
+
+  test_unnamed_onFunctionType() async {
+    await assertNoErrorsInCode('''
+extension on int Function(String) {}
+''');
+    var extendedType = findNode.typeAnnotation('Function');
+    assertType(extendedType, 'int Function(String)');
+    var returnType = findNode.typeAnnotation('int');
+    assertType(returnType, 'int');
+    var parameterType = findNode.typeAnnotation('String');
+    assertType(parameterType, 'String');
+  }
+
+  test_unnamed_onInterface() async {
+    await assertNoErrorsInCode('''
+class C { }
+extension on C {}
+''');
+    var extendedType = findNode.typeAnnotation('C {}');
+    assertElement(extendedType, findElement.class_('C'));
+    assertType(extendedType, 'C');
+  }
+
+  test_unnamed_onMixin() async {
+    await assertNoErrorsInCode('''
+mixin M {
+}
+extension on M {}
+''');
+    var extendedType = findNode.typeAnnotation('M {}');
+    assertElement(extendedType, findElement.mixin('M'));
+    assertType(extendedType, 'M');
+  }
+}
+
 /// Tests that extension members can be correctly resolved when referenced
 /// by code external to the extension declaration.
 @reflectiveTest
@@ -602,27 +646,6 @@
     assertType(access, 'int');
   }
 
-  test_instance_getter_with_setter() async {
-    await assertNoErrorsInCode('''
-class C {}
-
-extension E on C {
-  int get a => 1;
-}
-
-extension E2 on C {
-  set a(int v) { }
-}
-
-f(C c) {
-  print(c.a);
-}
-''');
-    var access = findNode.prefixed('c.a');
-    assertElement(access, findElement.getter('a'));
-    assertType(access, 'int');
-  }
-
   test_instance_getterInvoked_fromExtension_functionType() async {
     await assertNoErrorsInCode('''
 extension E on int Function(int) {
@@ -1083,27 +1106,6 @@
     assertElement(access, findElement.setter('a'));
   }
 
-  test_instance_setter_with_getter() async {
-    await assertNoErrorsInCode('''
-class C {}
-
-extension E on C {
-  int get a => 1;
-}
-
-extension E2 on C {
-  set a(int v) { }
-}
-
-f(C c) {
-  print(c.a = 1);
-}
-''');
-    var access = findNode.prefixed('c.a');
-    assertElement(access, findElement.setter('a'));
-    assertType(access, 'int');
-  }
-
   test_instance_tearoff_fromExtension_functionType() async {
     await assertNoErrorsInCode('''
 extension E on int Function(int) {
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
index cb1bd80..e76fb1b 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
@@ -556,6 +556,10 @@
 
   void validateOverride({List<DartType> typeArguments}) {
     expect(extensionOverride.extensionName.staticElement, extension);
+
+    expect(extensionOverride.staticType, isNull);
+    expect(extensionOverride.extensionName.staticType, isNull);
+
     if (typeArguments == null) {
       expect(extensionOverride.typeArguments, isNull);
     } else {
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
new file mode 100644
index 0000000..4a95d53
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(IndexExpressionTest);
+    defineReflectiveTests(IndexExpressionWithNnbdTest);
+  });
+}
+
+@reflectiveTest
+class IndexExpressionTest extends DriverResolutionTest {
+  test_read() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  bool operator[](int index) => false;
+}
+
+main(A a) {
+  a[0];
+}
+''');
+
+    var indexElement = findElement.method('[]');
+
+    var indexExpression = findNode.index('a[0]');
+    assertElement(indexExpression, indexElement);
+    assertAuxElement(indexExpression, null);
+    assertParameterElement(
+      indexExpression.index,
+      indexElement.parameters[0],
+    );
+    assertType(indexExpression, 'bool');
+  }
+
+  test_read_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  T operator[](int index) => null;
+}
+
+main(A<double> a) {
+  a[0];
+}
+''');
+
+    var indexElement = findElement.method('[]');
+
+    var indexExpression = findNode.index('a[0]');
+    assertMember(indexExpression, indexElement, {'T': 'double'});
+    assertAuxElement(indexExpression, null);
+    assertParameterElement(
+      indexExpression.index,
+      indexElement.parameters[0],
+    );
+    assertType(indexExpression, 'double');
+  }
+
+  test_readWrite() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  num operator[](int index) => 0;
+  void operator[]=(int index, num value) {}
+}
+
+main(A a) {
+  a[0] += 1.2;
+}
+''');
+
+    var indexElement = findElement.method('[]');
+    var indexEqElement = findElement.method('[]=');
+    var numPlusElement = numElement.getMethod('+');
+
+    var indexExpression = findNode.index('a[0]');
+    assertElement(indexExpression, indexEqElement);
+    assertAuxElement(indexExpression, indexElement);
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'num');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, numPlusElement);
+    assertType(assignment, 'num');
+    assertParameterElement(
+      assignment.rightHandSide,
+      numPlusElement.parameters[0],
+    );
+  }
+
+  test_readWrite_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  T operator[](int index) => null;
+  void operator[]=(int index, T value) {}
+}
+
+main(A<double> a) {
+  a[0] += 1.2;
+}
+''');
+
+    var indexElement = findElement.method('[]');
+    var indexEqElement = findElement.method('[]=');
+    var doublePlusElement = doubleElement.getMethod('+');
+
+    var indexExpression = findNode.index('a[0]');
+    assertMember(indexExpression, indexEqElement, {'T': 'double'});
+    assertAuxMember(indexExpression, indexElement, {'T': 'double'});
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'double');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, doublePlusElement);
+    assertType(assignment, 'double');
+    assertParameterElement(
+      assignment.rightHandSide,
+      doublePlusElement.parameters[0],
+    );
+  }
+
+  test_write() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  void operator[]=(int index, num value) {}
+}
+
+main(A a) {
+  a[0] = 1.2;
+}
+''');
+
+    var indexEqElement = findElement.method('[]=');
+
+    var indexExpression = findNode.index('a[0]');
+    assertElement(indexExpression, indexEqElement);
+    assertAuxElement(indexExpression, null);
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'num');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, null);
+    assertType(assignment, 'double');
+    assertParameterElement(assignment.rightHandSide, null);
+  }
+
+  test_write_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  void operator[]=(int index, T value) {}
+}
+
+main(A<double> a) {
+  a[0] = 1.2;
+}
+''');
+
+    var indexEqElement = findElement.method('[]=');
+
+    var indexExpression = findNode.index('a[0]');
+    assertMember(indexExpression, indexEqElement, {'T': 'double'});
+    assertAuxElement(indexExpression, null);
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'double');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, null);
+    assertType(assignment, 'double');
+    assertParameterElement(assignment.rightHandSide, null);
+  }
+}
+
+@reflectiveTest
+class IndexExpressionWithNnbdTest extends IndexExpressionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+  @override
+  bool get typeToStringWithNullability => true;
+
+  test_read_nullable() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  bool operator[](int index) => false;
+}
+
+main(A? a) {
+  a?.[0];
+}
+''');
+
+    var indexElement = findElement.method('[]');
+
+    var indexExpression = findNode.index('a?.[0]');
+    assertElement(indexExpression, indexElement);
+    assertAuxElement(indexExpression, null);
+    assertType(indexExpression, 'bool?');
+  }
+
+  test_readWrite_nullable() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  num operator[](int index) => 0;
+  void operator[]=(int index, num value) {}
+}
+
+main(A? a) {
+  a?.[0] += 1.2;
+}
+''');
+
+    var indexElement = findElement.method('[]');
+    var indexEqElement = findElement.method('[]=');
+    var numPlusElement = numElement.getMethod('+');
+
+    var indexExpression = findNode.index('a?.[0]');
+    assertElement(indexExpression, indexEqElement);
+    assertAuxElement(indexExpression, indexElement);
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'num');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, numPlusElement);
+    assertType(assignment, 'num?');
+    assertParameterElement(
+      assignment.rightHandSide,
+      numPlusElement.parameters[0],
+    );
+  }
+
+  test_write_nullable() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  void operator[]=(int index, num value) {}
+}
+
+main(A? a) {
+  a?.[0] = 1.2;
+}
+''');
+
+    var indexEqElement = findElement.method('[]=');
+
+    var indexExpression = findNode.index('a?.[0]');
+    assertElement(indexExpression, indexEqElement);
+    assertAuxElement(indexExpression, null);
+    assertParameterElement(
+      indexExpression.index,
+      indexEqElement.parameters[0],
+    );
+    assertType(indexExpression, 'num');
+
+    var assignment = indexExpression.parent as AssignmentExpression;
+    assertElement(assignment, null);
+    assertType(assignment, 'double?');
+    assertParameterElement(assignment.rightHandSide, null);
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 827c61b..68895de 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -317,7 +317,7 @@
   M();
 }
 ''', [
-      error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+      error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
       error(StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1, 27, 1),
     ]);
   }
@@ -329,7 +329,7 @@
   M(this.f);
 }
 ''', [
-      error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+      error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
     ]);
 
     var element = findElement.mixin('M');
@@ -830,7 +830,7 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
+      error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
     ]);
 
     // Even though it is an error for a mixin to declare a constructor,
@@ -879,7 +879,7 @@
   new M.named();
 }
 ''', [
-      error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
+      error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
       error(CompileTimeErrorCode.MIXIN_INSTANTIATE, 43, 1),
     ]);
 
@@ -1240,10 +1240,10 @@
 
 abstract class X extends A with U1, U2, M {}
 ''', [
-      error(StaticWarningCode.UNDEFINED_CLASS, 121, 2),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 121, 2),
       error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 121, 2),
       error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 125, 2),
-      error(StaticWarningCode.UNDEFINED_CLASS, 125, 2),
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 125, 2),
       error(
           CompileTimeErrorCode
               .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 3fd1ab2..bae934f 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -70,6 +71,26 @@
     newFile('/test/lib/test.dart', content: content);
   }
 
+  void assertAuxElement(AstNode node, Element expected) {
+    var auxElements = getNodeAuxElements(node);
+    expect(auxElements?.staticElement, same(expected));
+  }
+
+  void assertAuxMember(
+    Expression node,
+    Element expectedBase,
+    Map<String, String> expectedSubstitution,
+  ) {
+    var actual = getNodeAuxElements(node)?.staticElement as ExecutableMember;
+
+    expect(actual.baseElement, same(expectedBase));
+
+    var actualMapString = actual.substitution.map.map(
+      (k, v) => MapEntry(k.name, '$v'),
+    );
+    expect(actualMapString, expectedSubstitution);
+  }
+
   /// Assert that the given [identifier] is a reference to a class, in the
   /// form that is not a separate expression, e.g. in a static method
   /// invocation like `C.staticMethod()`, or a type annotation `C c = null`.
@@ -352,6 +373,13 @@
     assertTestErrorsWithCodes(const <ErrorCode>[]);
   }
 
+  void assertParameterElement(
+    Expression expression,
+    ParameterElement expected,
+  ) {
+    expect(expression.staticParameterElement, expected);
+  }
+
   void assertPropertyAccess(
     PropertyAccess access,
     Element expectedElement,
@@ -436,6 +464,14 @@
               const <ExpectedMessage>[]}) =>
       ExpectedError(code, offset, length, expectedMessages: expectedMessages);
 
+  AuxiliaryElements getNodeAuxElements(AstNode node) {
+    if (node is IndexExpression) {
+      return node.auxiliaryElements;
+    } else {
+      fail('Unsupported node: (${node.runtimeType}) $node');
+    }
+  }
+
   Element getNodeElement(AstNode node) {
     if (node is Annotation) {
       return node.element;
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 8261f8b..80bb8fb 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -23,6 +23,7 @@
 import 'generic_function_type_test.dart' as generic_function_type;
 import 'generic_type_alias_test.dart' as generic_type_alias;
 import 'import_prefix_test.dart' as import_prefix;
+import 'index_expression_test.dart' as index_expression;
 import 'instance_creation_test.dart' as instance_creation;
 import 'instance_member_inference_class_test.dart'
     as instance_member_inference_class;
@@ -59,6 +60,7 @@
     generic_function_type.main();
     generic_type_alias.main();
     import_prefix.main();
+    index_expression.main();
     instance_creation.main();
     instance_member_inference_class.main();
     instance_member_inference_mixin.main();
diff --git a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
index 6a46b65..a6894c5 100644
--- a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
@@ -40,43 +40,112 @@
     ]);
   }
 
-  test_getter() async {
+  test_getter_getter() async {
     await assertErrorsInCode('''
-class A {}
-
-extension E1 on A {
+extension E1 on int {
   void get a => 1;
 }
 
-extension E2 on A {
+extension E2 on int {
   void get a => 2;
 }
 
-f(A a) {
-  a.a;
+f() {
+  0.a;
 }
 ''', [
-      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 109, 1),
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 98, 1),
     ]);
+    var access = findNode.propertyAccess('0.a');
+    assertElementNull(access);
+    assertTypeDynamic(access);
   }
 
-  test_method() async {
+  test_getter_method() async {
     await assertErrorsInCode('''
-class A {}
+extension E on int {
+  int get a => 1;
+}
 
-extension E1 on A {
+extension E2 on int {
   void a() {}
 }
 
-extension E2 on A {
-  void a() {}
-}
-
-f(A a) {
-  a.a();
+f() {
+  0.a;
 }
 ''', [
-      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 99, 1),
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 91, 1),
+    ]);
+    var access = findNode.propertyAccess('0.a');
+    assertElementNull(access);
+    assertTypeDynamic(access);
+  }
+
+  test_getter_setter() async {
+    await assertErrorsInCode('''
+extension E on int {
+  int get a => 1;
+}
+
+extension E2 on int {
+  set a(int v) { }
+}
+
+f() {
+  0.a;
+}
+''', [
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 96, 1),
+    ]);
+    var access = findNode.propertyAccess('0.a');
+    assertElementNull(access);
+    assertTypeDynamic(access);
+  }
+
+  test_method_method() async {
+    await assertErrorsInCode('''
+extension E1 on int {
+  void a() {}
+}
+
+extension E2 on int {
+  void a() {}
+}
+
+f() {
+  0.a();
+}
+''', [
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 88, 1),
+    ]);
+    var invocation = findNode.methodInvocation('0.a()');
+    assertElementNull(invocation);
+    assertTypeDynamic(invocation);
+  }
+
+  test_noMoreSpecificExtension() async {
+    await assertErrorsInCode(r'''
+class Target<T> {}
+
+class SubTarget<T> extends Target<T> {}
+
+extension E1 on SubTarget<Object> {
+  int get foo => 0;
+}
+
+extension E2<T> on Target<T> {
+  int get foo => 0;
+}
+
+f(SubTarget<num> t) {
+  // The instantiated on type of `E1(t)` is `SubTarget<Object>`.
+  // The instantiated on type of `E2(t)` is `Target<num>`.
+  // Neither is a subtype of the other, so the resolution is ambiguous.
+  t.foo;
+}
+''', [
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 396, 3),
     ]);
   }
 
@@ -135,23 +204,24 @@
     ]);
   }
 
-  test_setter() async {
+  test_setter_setter() async {
     await assertErrorsInCode('''
-class A {}
-
-extension E1 on A {
+extension E1 on int {
   set a(x) {}
 }
 
-extension E2 on A {
+extension E2 on int {
   set a(x) {}
 }
 
-f(A a) {
-  a.a = 3;
+f() {
+  0.a = 3;
 }
 ''', [
-      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 99, 1),
+      error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 88, 1),
     ]);
+    var access = findNode.propertyAccess('0.a');
+    assertElementNull(access);
+    assertTypeDynamic(access);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
index cef7998..9b25380 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.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/src/dart/error/hint_codes.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -11,6 +13,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AssignmentToFinalLocalTest);
+    defineReflectiveTests(AssignmentToFinalLocalWithNnbdTest);
   });
 }
 
@@ -27,6 +30,18 @@
     ]);
   }
 
+  test_localVariable_inForEach() async {
+    await assertErrorsInCode('''
+f() {
+  final x = 0;
+  for (x in <int>[1, 2]) {
+    print(x);
+  }
+}''', [
+      error(StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL, 28, 1),
+    ]);
+  }
+
   test_localVariable_plusEq() async {
     await assertErrorsInCode('''
 f() {
@@ -113,18 +128,6 @@
     ]);
   }
 
-  test_localVariable_inForEach() async {
-    await assertErrorsInCode('''
-f() {
-  final x = 0;
-  for (x in <int>[1, 2]) {
-    print(x);
-  }
-}''', [
-      error(StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL, 28, 1),
-    ]);
-  }
-
   test_topLevelVariable() async {
     await assertErrorsInCode('''
 final x = 0;
@@ -133,3 +136,33 @@
     ]);
   }
 }
+
+@reflectiveTest
+class AssignmentToFinalLocalWithNnbdTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+  test_localVariable_late() async {
+    await assertNoErrorsInCode('''
+void f() {
+  late final int a;
+  late final int b = 0;
+  a = 1;
+  b = 1;
+}
+''');
+  }
+
+  test_topLevelVariable_late() async {
+    await assertNoErrorsInCode('''
+late final int a;
+late final int b = 0;
+void f() {
+  a = 1;
+  b = 1;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
index b2a4a05..cbe2f70 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
@@ -3,11 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
-import 'package:analyzer/src/error/codes.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -52,24 +52,28 @@
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
 
-  @failingTest
   test_field_late() async {
     await assertNoErrorsInCode('''
 class A {
-  final a;
+  late final int a;
+  late final int b = 0;
   void m() {
     a = 1;
+    b = 1;
   }
 }
 ''');
   }
 
-  @failingTest
-  test_localVariable_late() async {
+  test_field_static_late() async {
     await assertNoErrorsInCode('''
-void f() {
-  final a;
-  a = 1;
+class A {
+  static late final int a;
+  static late final int b = 0;
+  void m() {
+    a = 1;
+    b = 1;
+  }
 }
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart b/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart
new file mode 100644
index 0000000..774ccd0
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/extension_method_test.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(BuiltinIdentifierAsExtensionNameTest);
+  });
+}
+
+@reflectiveTest
+class BuiltinIdentifierAsExtensionNameTest extends BaseExtensionMethodsTest {
+  test_error_builtInIdentifierAsExtensionName() async {
+    await assertErrorsInCode(
+      r'''
+extension as on Object {}
+''',
+      [
+        error(
+            CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME, 10, 2),
+      ],
+    );
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart
new file mode 100644
index 0000000..eca8efc
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+//    defineReflectiveTests(ConstNotInitializedTest);
+    defineReflectiveTests(ConstNotInitializedWithExtensionMethodsTest);
+//    defineReflectiveTests(ConstNotInitializedWithNnbdTest);
+  });
+}
+
+@reflectiveTest
+class ConstNotInitializedTest extends DriverResolutionTest {}
+
+@reflectiveTest
+class ConstNotInitializedWithExtensionMethodsTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_instance() async {
+    await assertErrorsInCode('''
+extension E on String {
+  static const F;
+}''', [
+      error(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 39, 1),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ConstNotInitializedWithNnbdTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart b/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart
new file mode 100644
index 0000000..cd9731d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ExtensionAsExpressionTest);
+  });
+}
+
+@reflectiveTest
+class ExtensionAsExpressionTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_prefixedIdentifier() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {}
+''');
+    await assertErrorsInCode('''
+import 'a.dart' as p;
+var v = p.E;
+''', [
+      error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 3),
+    ]);
+    assertTypeDynamic(findNode.simple('E;'));
+    assertTypeDynamic(findNode.prefixed('p.E;'));
+  }
+
+  test_simpleIdentifier() async {
+    await assertErrorsInCode('''
+extension E on int {}
+var v = E;
+''', [
+      error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 1),
+    ]);
+    assertTypeDynamic(findNode.simple('E;'));
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
index 3426dd9..55c639f 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -28,7 +28,7 @@
   bool get isPalindrome;
 }
 ''', [
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 35, 12),
+      error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 35, 12),
     ]);
   }
 
@@ -38,7 +38,7 @@
   String reversed();
 }
 ''', [
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 33, 8),
+      error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 33, 8),
     ]);
   }
 
@@ -54,7 +54,7 @@
   String operator -(String otherString);
 }
 ''', [
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 42, 1),
+      error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 42, 1),
     ]);
   }
 
@@ -64,7 +64,7 @@
   set length(int newLength);
 }
 ''', [
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 30, 6),
+      error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 30, 6),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
index b7d66b5..6334a96 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -27,7 +27,7 @@
 extension E on String {
   E.named() : super();
 }
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 28, 5)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
   }
 
   test_none() async {
@@ -41,6 +41,6 @@
 extension E on String {
   E() : super();
 }
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
index f7916c2..416293a 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -27,11 +27,7 @@
 extension E on String {
   String one, two, three;
 }
-''', [
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 3),
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 38, 3),
-      error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 43, 5)
-    ]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 3)]);
   }
 
   test_none() async {
@@ -45,7 +41,7 @@
 extension E on String {
   String s;
 }
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 1)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 1)]);
   }
 
   test_static() async {
diff --git a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
index 76dbce0..a16250c 100644
--- a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
@@ -22,7 +22,8 @@
   (int x, {int y}) {} (0, 1);
 }
 ''', [
-      error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 31, 6),
+      error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 31,
+          6),
     ]);
   }
 
@@ -33,8 +34,8 @@
   f(0, 1, '2');
 }
 ''', [
-      error(
-          StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 25, 11),
+      error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 25,
+          11),
     ]);
   }
 }
@@ -48,7 +49,7 @@
   f(0, 1, '2');
 }
 ''', [
-      error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS, 19, 11),
+      error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS, 19, 11),
     ]);
   }
 
@@ -58,7 +59,7 @@
   (int x) {} (0, 1);
 }
 ''', [
-      error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS, 22, 6),
+      error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS, 22, 6),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
index 5be052f..3c0937a 100644
--- a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
@@ -13,6 +13,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(FinalNotInitializedTest);
+    defineReflectiveTests(FinalNotInitializedWithExtensionMethodsTest);
     defineReflectiveTests(FinalNotInitializedWithNnbdTest);
   });
 }
@@ -57,6 +58,23 @@
 }
 
 @reflectiveTest
+class FinalNotInitializedWithExtensionMethodsTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_static() async {
+    await assertErrorsInCode('''
+extension E on String {
+  static final F;
+}''', [
+      error(StaticWarningCode.FINAL_NOT_INITIALIZED, 39, 1),
+    ]);
+  }
+}
+
+@reflectiveTest
 class FinalNotInitializedWithNnbdTest extends DriverResolutionTest {
   @override
   AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
diff --git a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
index d32baeb..c5d1d06 100644
--- a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
@@ -25,7 +25,7 @@
 import 'lib1.dart' deferred as p;
 var a = new p.A();
 ''', [
-      error(StaticWarningCode.IMPORT_OF_NON_LIBRARY, 20, 11),
+      error(CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, 20, 11),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart
new file mode 100644
index 0000000..baca673
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/package_mixin.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidRequiredNamedParamTest);
+  });
+}
+
+@reflectiveTest
+class InvalidRequiredNamedParamTest extends DriverResolutionTest
+    with PackageMixin {
+  @override
+  void setUp() {
+    super.setUp();
+    addMetaPackage();
+  }
+
+  test_namedParameter_withDefault() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m({@required a = 1}) => null;
+''', [
+      error(HintCode.INVALID_REQUIRED_NAMED_PARAM, 37, 15),
+    ]);
+  }
+
+  test_namedParameter_withDefault_asSecond() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(a, {@required b = 1}) => null;
+''', [
+      error(HintCode.INVALID_REQUIRED_NAMED_PARAM, 40, 15),
+    ]);
+  }
+
+  test_valid() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m1({a}) => null;
+m2({a = 5}) => null;
+m3({@required a}) => null;
+m4({a, @required b}) => null;
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
similarity index 62%
rename from pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
rename to pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
index 739f3e5..5782b42 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
@@ -10,35 +10,26 @@
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(InvalidRequiredParamTest);
+    defineReflectiveTests(InvalidRequiredOptionalPositionalParamTest);
   });
 }
 
 @reflectiveTest
-class InvalidRequiredParamTest extends DriverResolutionTest with PackageMixin {
+class InvalidRequiredOptionalPositionalParamTest extends DriverResolutionTest
+    with PackageMixin {
   @override
   void setUp() {
     super.setUp();
     addMetaPackage();
   }
 
-  test_namedParameter_withDefault() async {
-    await assertErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-m({@required a = 1}) => null;
-''', [
-      error(HintCode.INVALID_REQUIRED_PARAM, 37, 15),
-    ]);
-  }
-
   test_positionalParameter_noDefault() async {
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
 m([@required a]) => null;
 ''', [
-      error(HintCode.INVALID_REQUIRED_PARAM, 37, 11),
+      error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 11),
     ]);
   }
 
@@ -48,30 +39,35 @@
 
 m([@required a = 1]) => null;
 ''', [
-      error(HintCode.INVALID_REQUIRED_PARAM, 37, 15),
+      error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 15),
     ]);
   }
 
-  test_requiredParameter() async {
+  test_positionalParameter_noDefault_asSecond() async {
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
-m(@required a) => null;
+m(a, [@required b]) => null;
 ''', [
-      error(HintCode.INVALID_REQUIRED_PARAM, 36, 11),
+      error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 40, 11),
+    ]);
+  }
+
+  test_positionalParameter_withDefault_withTwo() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m([a, @required b = 1]) => null;
+''', [
+      error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 40, 15),
     ]);
   }
 
   test_valid() async {
     await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-m1() => null;
-m2(a) => null;
-m3([a]) => null;
-m4({a}) => null;
-m5({@required a}) => null;
-m6({a, @required b}) => null;
+m1([a]) => null;
+m2([a = 1]) => null;
+m3([a, b]) => null;
 ''');
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart
new file mode 100644
index 0000000..5717328
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/package_mixin.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidRequiredPositionalParamTest);
+  });
+}
+
+@reflectiveTest
+class InvalidRequiredPositionalParamTest extends DriverResolutionTest
+    with PackageMixin {
+  @override
+  void setUp() {
+    super.setUp();
+    addMetaPackage();
+  }
+
+  test_requiredPositionalParameter() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(@required a) => null;
+''', [
+      error(HintCode.INVALID_REQUIRED_POSITIONAL_PARAM, 36, 11),
+    ]);
+  }
+
+  test_requiredPositionalParameter_asSecond() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(a, @required b) => null;
+''', [
+      error(HintCode.INVALID_REQUIRED_POSITIONAL_PARAM, 39, 11),
+    ]);
+  }
+
+  test_valid() async {
+    await assertNoErrorsInCode(r'''
+m1() => null;
+m2(a) => null;
+m3(a, b) => null;
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
index 0458e81..bd33642 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
@@ -2,7 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/test_utilities/package_mixin.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -11,6 +13,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InvalidUseOfProtectedMemberTest);
+    defineReflectiveTests(InvalidUseOfProtectedMember_InExtensionTest);
   });
 }
 
@@ -308,6 +311,9 @@
   }
 
   test_mixingIn_asParameter() async {
+    // TODO(srawlins): This test verifies that the analyzer **allows**
+    // protected members to be called from static members, which violates the
+    // protected spec.
     addMetaPackage();
     await assertNoErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -336,6 +342,9 @@
   }
 
   test_setter_outsideClassAndFile() async {
+    // TODO(srawlins): This test verifies that the analyzer **allows**
+    // protected members to be called on objects other than `this`, which
+    // violates the protected spec.
     addMetaPackage();
     newFile('/lib1.dart', content: r'''
 import 'package:meta/meta.dart';
@@ -425,3 +434,35 @@
     result = await resolveFile(convertPath(path));
   }
 }
+
+@reflectiveTest
+class InvalidUseOfProtectedMember_InExtensionTest
+    extends InvalidUseOfProtectedMemberTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_extension_outsideClassAndFile() async {
+    addMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(int i) {}
+}
+''');
+    newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+extension E on A {
+  e() {
+    a(7);
+  }
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/lib2.dart');
+    assertTestErrorsWithCodes([HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart
index f14c277..397fc3f 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.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/file_system/file_system.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/test_utilities/package_mixin.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -12,6 +14,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InvalidUseOfVisibleForTemplateMemberTest);
+    defineReflectiveTests(InvalidUseOfVisibleForTemplateMember_InExtensionTest);
   });
 }
 
@@ -227,3 +230,55 @@
     result = await resolveFile(convertPath(path));
   }
 }
+
+@reflectiveTest
+class InvalidUseOfVisibleForTemplateMember_InExtensionTest
+    extends InvalidUseOfVisibleForTemplateMemberTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_functionInExtension() async {
+    addAngularMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:angular_meta/angular_meta.dart';
+extension E on List {
+  @visibleForTemplate
+  int m() => 1;
+}
+''');
+    newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+  E([]).m();
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/lib2.dart');
+    assertTestErrorsWithCodes(
+        [HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER]);
+  }
+
+  test_functionInExtension_fromTemplate() async {
+    addAngularMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:angular_meta/angular_meta.dart';
+extension E on List {
+  @visibleForTemplate
+  int m() => 1;
+}
+''');
+    newFile('/lib1.template.dart', content: r'''
+import 'lib1.dart';
+void main() {
+  E([]).m();
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/lib1.template.dart');
+    assertNoTestErrors();
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
index 984fbcf..d61d928 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
@@ -2,7 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/test_utilities/package_mixin.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -11,12 +13,18 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InvalidUseOfVisibleForTestingMemberTest);
+    defineReflectiveTests(InvalidUseOfVisibleForTestingMember_InExtensionTest);
   });
 }
 
 @reflectiveTest
 class InvalidUseOfVisibleForTestingMemberTest extends DriverResolutionTest
     with PackageMixin {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
   test_constructor() async {
     addMetaPackage();
     newFile('/lib1.dart', content: r'''
@@ -210,6 +218,29 @@
         [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
   }
 
+  test_mixin() async {
+    addMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+mixin M {
+  @visibleForTesting
+  int m() => 1;
+}
+class C with M {}
+''');
+    newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+  C().m();
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/lib2.dart');
+    assertTestErrorsWithCodes(
+        [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
+  }
+
   test_topLevelFunction() async {
     addMetaPackage();
     newFile('/lib1.dart', content: r'''
@@ -237,3 +268,55 @@
     result = await resolveFile(convertPath(path));
   }
 }
+
+@reflectiveTest
+class InvalidUseOfVisibleForTestingMember_InExtensionTest
+    extends InvalidUseOfVisibleForTestingMemberTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_functionInExtension() async {
+    addMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+extension E on List {
+  @visibleForTesting
+  int m() => 1;
+}
+''');
+    newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+  E([]).m();
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/lib2.dart');
+    assertTestErrorsWithCodes(
+        [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
+  }
+
+  test_functionInExtension_fromTestDirectory() async {
+    addMetaPackage();
+    newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+extension E on List {
+  @visibleForTesting
+  int m() => 1;
+}
+''');
+    newFile('/test/test.dart', content: r'''
+import '../lib1.dart';
+void main() {
+  E([]).m();
+}
+''');
+
+    await _resolveTestFile('/lib1.dart');
+    await _resolveTestFile('/test/test.dart');
+    assertNoTestErrors();
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart b/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
index 9ff91b1..7eb1b7d 100644
--- a/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
@@ -2,7 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(NotATypeTest);
+    defineReflectiveTests(NotATypeWithExtensionMethodsTest);
   });
 }
 
@@ -26,3 +29,19 @@
     ]);
   }
 }
+
+@reflectiveTest
+class NotATypeWithExtensionMethodsTest extends NotATypeTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+  test_extension() async {
+    await assertErrorsInCode('''
+extension E on int {}
+E a;
+''', [error(StaticWarningCode.NOT_A_TYPE, 22, 1)]);
+    assertTypeDynamic(findNode.simple('E a;'));
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
similarity index 70%
rename from pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart
rename to pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
index bea8216..8f04ad1 100644
--- a/pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
@@ -9,18 +9,18 @@
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(NotEnoughRequiredArgumentsTest);
+    defineReflectiveTests(NotEnoughPositionalArgumentsTest);
   });
 }
 
 @reflectiveTest
-class NotEnoughRequiredArgumentsTest extends DriverResolutionTest {
+class NotEnoughPositionalArgumentsTest extends DriverResolutionTest {
   test_functionExpression() async {
     await assertErrorsInCode('''
 main() {
   (int x) {} ();
 }''', [
-      error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 22, 2),
+      error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 22, 2),
     ]);
   }
 
@@ -30,7 +30,7 @@
 main() {
   f();
 }''', [
-      error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 34, 2),
+      error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 34, 2),
     ]);
   }
 
@@ -41,7 +41,7 @@
 main() {
   getter();
 }''', [
-      error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 65, 2),
+      error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 65, 2),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
index ccb37f7..2e2c468 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
@@ -86,6 +86,14 @@
     ]);
   }
 
+  test_late() async {
+    await assertNoErrorsInCode('''
+class A {
+  late int x;
+}
+''');
+  }
+
   test_notAllConstructors() async {
     await assertErrorsInCode('''
 class A {
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
index ef60224..2e028b6 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
@@ -39,6 +39,14 @@
 ''');
   }
 
+  test_staticField_late() async {
+    await assertNoErrorsInCode('''
+class A {
+  static late int v;
+}
+''');
+  }
+
   test_staticField_noInitializer() async {
     await assertErrorsInCode('''
 class A {
diff --git a/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
index c688e3b..e181529 100644
--- a/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
@@ -23,7 +23,7 @@
 class B {
   factory B() = A.name;
 }''', [
-      error(StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 59, 6),
+      error(CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 59, 6),
     ]);
   }
 
@@ -35,7 +35,7 @@
 class B {
   factory B() = A;
 }''', [
-      error(StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 64, 1),
+      error(CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 64, 1),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart b/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
index 39c83ab..38e1b35 100644
--- a/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
@@ -21,7 +21,7 @@
   int A;
   factory B() = A;
 }''', [
-      error(StaticWarningCode.REDIRECT_TO_NON_CLASS, 35, 1),
+      error(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, 35, 1),
     ]);
   }
 
@@ -30,7 +30,7 @@
 class B {
   factory B() = A;
 }''', [
-      error(StaticWarningCode.REDIRECT_TO_NON_CLASS, 26, 1),
+      error(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, 26, 1),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart b/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
index b356cfd..3b26ce9 100644
--- a/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
@@ -23,14 +23,24 @@
         sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
 
   test_binaryOperator_inMethod() async {
-    // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
     await assertErrorsInCode('''
 extension E on int {
   int plusOne() => super + 1;
 }
 ''', [
       error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 40, 5),
-      error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 46, 1),
+    ]);
+  }
+
+  test_binaryOperator_withGenericExtendedType() async {
+    await assertErrorsInCode('''
+extension <T> on T {
+  f() {
+    super + 1;
+  }
+}
+''', [
+      error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 33, 5),
     ]);
   }
 
@@ -51,7 +61,6 @@
   }
 
   test_indexOperator_inMethod() async {
-    // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
     await assertErrorsInCode('''
 class C {
   int operator[](int i) => 0;
@@ -61,7 +70,6 @@
 }
 ''', [
       error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 80, 5),
-      error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 85, 3),
     ]);
   }
 
@@ -76,7 +84,6 @@
   }
 
   test_prefixOperator_inGetter() async {
-    // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
     await assertErrorsInCode('''
 class C {
   C operator-() => this;
@@ -85,7 +92,6 @@
   C get negated => -super;
 }
 ''', [
-      error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 75, 1),
       error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 76, 5),
     ]);
   }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 749012b..b953550 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -20,6 +20,8 @@
 import 'assignment_to_type_test.dart' as assignment_to_type;
 import 'async_keyword_used_as_identifier_test.dart'
     as async_keyword_used_as_identifier;
+import 'builtin_identifier_as_extension_name_test.dart'
+    as builtin_as_extension_name;
 import 'can_be_null_after_null_aware_test.dart' as can_be_null_after_null_aware;
 import 'case_block_not_terminated_test.dart' as case_block_not_terminated;
 import 'cast_to_non_type_test.dart' as cast_to_non_type;
@@ -34,6 +36,7 @@
 import 'const_eval_throws_exception_test.dart' as const_eval_throws_exception;
 import 'const_map_key_expression_type_implements_equals_test.dart'
     as const_map_key_expression_type_implements_equals;
+import 'const_not_initialized_test.dart' as const_not_initialized;
 import 'const_set_element_type_implements_equals_test.dart'
     as const_set_element_type_implements_equals;
 import 'const_spread_expected_list_or_set_test.dart'
@@ -62,6 +65,7 @@
     as export_suplicated_library_named;
 import 'expression_in_map_test.dart' as expression_in_map;
 import 'extends_non_class_test.dart' as extends_non_class;
+import 'extension_as_expression_test.dart' as extension_as_expression;
 import 'extension_conflicting_static_and_instance_test.dart'
     as extension_conflicting_static_and_instance;
 import 'extension_declares_abstract_method_test.dart'
@@ -121,7 +125,11 @@
     as invalid_override_different_default_values_positional;
 import 'invalid_override_test.dart' as invalid_override;
 import 'invalid_reference_to_this_test.dart' as invalid_reference_to_this;
-import 'invalid_required_param_test.dart' as invalid_required_param;
+import 'invalid_required_named_param_test.dart' as invalid_required_named_param;
+import 'invalid_required_optional_positional_param_test.dart'
+    as invalid_required_optional_positional_param;
+import 'invalid_required_positional_param_test.dart'
+    as invalid_required_positional_param;
 import 'invalid_sealed_annotation_test.dart' as invalid_sealed_annotation;
 import 'invalid_use_of_covariant_in_extension_test.dart'
     as invalid_use_of_covariant_in_extension;
@@ -189,8 +197,8 @@
 import 'not_a_type_test.dart' as not_a_type;
 import 'not_assigned_potentially_non_nullable_local_variable_test.dart'
     as not_assigned_potentially_non_nullable_local_variable;
-import 'not_enough_required_arguments_test.dart'
-    as not_enough_required_arguments;
+import 'not_enough_positional_arguments_test.dart'
+    as not_enough_positional_arguments;
 import 'not_initialized_non_nullable_instance_field_test.dart'
     as not_initialized_non_nullable_instance_field;
 import 'not_initialized_non_nullable_variable_test.dart'
@@ -313,6 +321,7 @@
     assignment_to_method.main();
     assignment_to_type.main();
     async_keyword_used_as_identifier.main();
+    builtin_as_extension_name.main();
     can_be_null_after_null_aware.main();
     case_block_not_terminated.main();
     cast_to_non_type.main();
@@ -322,6 +331,7 @@
     const_constructor_with_mixin_with_field.main();
     const_eval_throws_exception.main();
     const_map_key_expression_type_implements_equals.main();
+    const_not_initialized.main();
     const_set_element_type_implements_equals.main();
     const_spread_expected_list_or_set.main();
     const_spread_expected_map.main();
@@ -344,6 +354,7 @@
     export_suplicated_library_named.main();
     expression_in_map.main();
     extends_non_class.main();
+    extension_as_expression.main();
     extension_conflicting_static_and_instance.main();
     extension_declares_abstract_method.main();
     extension_declares_constructor.main();
@@ -380,7 +391,9 @@
     invalid_override_different_default_values_positional.main();
     invalid_override.main();
     invalid_reference_to_this.main();
-    invalid_required_param.main();
+    invalid_required_named_param.main();
+    invalid_required_optional_positional_param.main();
+    invalid_required_positional_param.main();
     invalid_sealed_annotation.main();
     invalid_use_of_covariant_in_extension.main();
     invalid_use_of_never_value.main();
@@ -431,7 +444,7 @@
     non_void_return_for_setter.main();
     not_a_type.main();
     not_assigned_potentially_non_nullable_local_variable.main();
-    not_enough_required_arguments.main();
+    not_enough_positional_arguments.main();
     not_initialized_non_nullable_instance_field.main();
     not_initialized_non_nullable_variable.main();
     not_iterable_spread.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
index 6f2981b..a5176b9 100644
--- a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -21,6 +22,9 @@
   AnalysisOptionsImpl get analysisOptions =>
       AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
 
+  @override
+  bool get typeToStringWithNullability => true;
+
   test_and_nonNullable() async {
     await assertNoErrorsInCode(r'''
 m() {
@@ -70,6 +74,120 @@
     ]);
   }
 
+  test_assignment_eq_propertyAccess3_short1() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  A(this.x);
+}
+
+class B {
+  final A? a;
+  B(this.a);
+}
+
+m(B b) {
+  b.a?.x = 1;
+  b.a.x = 2;
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 100, 3),
+    ]);
+    var assignment1 = findNode.assignment('b.a?.x = 1');
+    var assignment2 = findNode.assignment('b.a.x = 2');
+    assertType(assignment1.leftHandSide, 'int');
+    assertType(assignment2.leftHandSide, 'int');
+    assertType(assignment1, 'int?');
+    assertType(assignment2, 'int');
+  }
+
+  test_assignment_eq_simpleIdentifier() async {
+    await assertNoErrorsInCode(r'''
+m(int x, int? y) {
+  x = 0;
+  y = 0;
+}
+''');
+    var assignment1 = findNode.assignment('x =');
+    var assignment2 = findNode.assignment('y =');
+    assertType(assignment1.leftHandSide, 'int');
+    assertType(assignment2.leftHandSide, 'int?');
+    assertType(assignment1, 'int');
+    assertType(assignment2, 'int');
+  }
+
+  test_assignment_plusEq_propertyAccess3() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  int? y;
+  A(this.x);
+}
+
+class B {
+  final A a;
+  B(this.a);
+}
+
+m(B b) {
+  b.a.x += 0;
+  b.a.y += 0;
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 109, 5),
+    ]);
+    var assignment1 = findNode.assignment('b.a.x +=');
+    var assignment2 = findNode.assignment('b.a.y +=');
+    assertType(assignment1.leftHandSide, 'int');
+    assertType(assignment2.leftHandSide, 'int?');
+    assertType(assignment1, 'int');
+    assertType(assignment2, 'int');
+  }
+
+  test_assignment_plusEq_propertyAccess3_short1() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  A(this.x);
+}
+
+class B {
+  final A? a;
+  B(this.a);
+}
+
+m(B b) {
+  b.a?.x += 1;
+  b.a.x += 2;
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+    ]);
+    var assignment1 = findNode.assignment('b.a?.x += 1');
+    var assignment2 = findNode.assignment('b.a.x += 2');
+    assertType(assignment1.leftHandSide, 'int');
+    assertType(assignment2.leftHandSide, 'int');
+    assertType(assignment1, 'int?');
+    assertType(assignment2, 'int');
+  }
+
+  test_assignment_plusEq_simpleIdentifier() async {
+    await assertErrorsInCode(r'''
+m(int x, int? y) {
+  x += 0;
+  y += 0;
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 31, 1),
+    ]);
+    var assignment1 = findNode.assignment('x +=');
+    var assignment2 = findNode.assignment('y +=');
+    assertType(assignment1.leftHandSide, 'int');
+    assertType(assignment2.leftHandSide, 'int?');
+    assertType(assignment1, 'int');
+    assertType(assignment2, 'int');
+  }
+
   test_await_nonNullable() async {
     await assertNoErrorsInCode(r'''
 m() async {
@@ -108,7 +226,7 @@
     ]);
   }
 
-  test_eq_nullable() async {
+  test_eqEq_nullable() async {
     await assertNoErrorsInCode(r'''
 m() {
   int? x;
@@ -613,6 +731,170 @@
     ]);
   }
 
+  test_read_propertyAccess2_short1() async {
+    await assertErrorsInCode(r'''
+class A {
+  final int x;
+  A(this.x);
+}
+
+m(A? a) {
+  a?.x; // 1
+  a.x; // 2
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 66, 1),
+    ]);
+    var propertyAccess1 = findNode.propertyAccess('a?.x; // 1');
+    var propertyAccess2 = findNode.prefixed('a.x; // 2');
+    assertType(propertyAccess1.target, 'A?');
+    assertType(propertyAccess2.prefix, 'A?');
+
+    assertType(propertyAccess1.propertyName, 'int');
+    assertType(propertyAccess2.identifier, 'int');
+
+    assertType(propertyAccess1, 'int?');
+    assertType(propertyAccess2, 'int');
+  }
+
+  test_read_propertyAccess3_short1() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  A(this.x);
+}
+
+class B {
+  final A? a;
+  B(this.a);
+}
+
+m(B b) {
+  b.a?.x; // 1
+  b.a.x; // 2
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+    ]);
+    var propertyAccess1 = findNode.propertyAccess('b.a?.x; // 1');
+    var propertyAccess2 = findNode.propertyAccess('b.a.x; // 2');
+    assertType(propertyAccess1.target, 'A?');
+    assertType(propertyAccess2.target, 'A?');
+
+    assertType(propertyAccess1.propertyName, 'int');
+    assertType(propertyAccess2.propertyName, 'int');
+
+    assertType(propertyAccess1, 'int?');
+    assertType(propertyAccess2, 'int');
+  }
+
+  test_read_propertyAccess3_short2() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  A(this.x);
+}
+
+class B {
+  final A a;
+  B(this.a);
+}
+
+m(B? b) {
+  b?.a.x; // 1
+  b.a.x; // 2
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 1),
+    ]);
+    var propertyAccess1 = findNode.propertyAccess('x; // 1');
+    var propertyAccess2 = findNode.propertyAccess('x; // 2');
+    assertType(propertyAccess1.target, 'A');
+    assertType(propertyAccess2.target, 'A');
+
+    assertType(propertyAccess1.propertyName, 'int');
+    assertType(propertyAccess2.propertyName, 'int');
+
+    assertType(propertyAccess1, 'int?');
+    assertType(propertyAccess2, 'int');
+  }
+
+  test_read_propertyAccess4_short1() async {
+    await assertErrorsInCode(r'''
+class A {
+  int x;
+  A(this.x);
+}
+
+class B {
+  final A? a;
+  B(this.a);
+}
+
+class C {
+  final B b;
+  C(this.b);
+}
+
+m(C c) {
+  c.b.a?.x; // 1
+  c.b.a.x; // 2
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 142, 5),
+    ]);
+    var propertyAccess1 = findNode.propertyAccess('x; // 1');
+    var propertyAccess2 = findNode.propertyAccess('x; // 2');
+    assertType(propertyAccess1.target, 'A?');
+    assertType(propertyAccess2.target, 'A?');
+
+    assertType(propertyAccess1.propertyName, 'int');
+    assertType(propertyAccess2.propertyName, 'int');
+
+    assertType(propertyAccess1, 'int?');
+    assertType(propertyAccess2, 'int');
+  }
+
+  test_read_propertyAccess4_short2() async {
+    await assertErrorsInCode(r'''
+class A {
+  final int x;
+  A(this.x);
+}
+
+class B {
+  final A a;
+  B(this.a);
+}
+
+class C {
+  final B? b;
+  C(this.b);
+}
+
+m(C c) {
+  c.b?.a.x; // 1
+  c.b.a.x; // 2
+}
+''', [
+      error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 148, 3),
+    ]);
+    var propertyAccess1 = findNode.propertyAccess('x; // 1');
+    var propertyAccess2 = findNode.propertyAccess('x; // 2');
+    PropertyAccess propertyAccess1t = propertyAccess1.target;
+    PropertyAccess propertyAccess2t = propertyAccess1.target;
+    assertType(propertyAccess1t.target, 'B?');
+    assertType(propertyAccess2t.target, 'B?');
+    assertType(propertyAccess1t, 'A');
+    assertType(propertyAccess2t, 'A');
+
+    assertType(propertyAccess1.propertyName, 'int');
+    assertType(propertyAccess2.propertyName, 'int');
+
+    assertType(propertyAccess1, 'int?');
+    assertType(propertyAccess2, 'int');
+  }
+
   test_spread_nonNullable() async {
     await assertNoErrorsInCode(r'''
 m() {
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
index 70860b2..840791c 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -310,34 +309,16 @@
   }
 
   test_typeParameter_bound() async {
-    try {
-      await assertErrorsInCode(r'''
+    await assertErrorsInCode(r'''
 class A<X> {}
 class B<X> extends A<void Function<Y extends X>()> {}
 ''', [
-        error(
-            CompileTimeErrorCode
-                .WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
-            22,
-            1),
-        error(
-            CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-            35,
-            28),
-      ]);
-      if (!AnalysisDriver.useSummary2) {
-        throw 'Test passed - expected to fail.';
-      }
-    } on String {
-      rethrow;
-    } catch (_) {
-      // TODO(scheglov) This code crashes with summary1.
-//    NoSuchMethodError: The getter 'bound' was called on null.
-//    Receiver: null
-//    Tried calling: bound
-//    #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
-//    #1      ErrorVerifier._checkForTypeParameterSupertypeOfItsBound (error_verifier.dart:5438:30)
-      if (AnalysisDriver.useSummary2) rethrow;
-    }
+      error(
+          CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+          22,
+          1),
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+          35, 28),
+    ]);
   }
 }
diff --git a/pkg/analyzer/test/src/fasta/message_coverage_test.dart b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
index 291f940..18a62fd 100644
--- a/pkg/analyzer/test/src/fasta/message_coverage_test.dart
+++ b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
@@ -6,13 +6,13 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:yaml/yaml.dart';
 
 import '../../generated/parser_fasta_test.dart';
+import '../../utils/package_root.dart' as package_root;
 
 main() {
   defineReflectiveSuite(() {
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 028dbdd..befdee3 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -206,4 +206,20 @@
 ''');
     assertCanBeConst("A([", true);
   }
+
+  void test_true_importedClass_defaultValue() async {
+    var aPath = convertPath('/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  final int a;
+  const A({int b = 1}) : a = b * 2;
+}
+''');
+    await resolve('''
+import 'a.dart';
+
+A f() => A();
+''');
+    assertCanBeConst("A();", true);
+  }
 }
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index a80aeb9..4e70ff2 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -1234,6 +1234,7 @@
       parameterNames: [],
       parameters: '()',
       parameterTypes: [],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 0,
       returnType: 'C',
     );
@@ -1244,6 +1245,7 @@
       parameterNames: [],
       parameters: '()',
       parameterTypes: [],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 0,
       returnType: 'C',
     );
@@ -1255,6 +1257,7 @@
       parameters: '()',
       parameterNames: [],
       parameterTypes: [],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 0,
       returnType: 'C',
     );
@@ -1267,6 +1270,7 @@
       parameters: '()',
       parameterNames: [],
       parameterTypes: [],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 0,
       returnType: 'C',
     );
@@ -1279,6 +1283,7 @@
       parameters: '(Map<String, int> p1, int p2, {double p3})',
       parameterNames: ['p1', 'p2', 'p3'],
       parameterTypes: ['Map<String, int>', 'int', 'double'],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 2,
       returnType: 'C',
     );
@@ -1291,6 +1296,7 @@
       parameters: '(this.f1, this.f2)',
       parameterNames: ['f1', 'f2'],
       parameterTypes: ['', ''],
+      relevanceTags: ['package:test/test.dart::C'],
       requiredParameterCount: 2,
       returnType: 'C',
     );
diff --git a/pkg/analyzer/test/src/summary/expr_builder_test.dart b/pkg/analyzer/test/src/summary/expr_builder_test.dart
index fcdb51f3..c73bee8 100644
--- a/pkg/analyzer/test/src/summary/expr_builder_test.dart
+++ b/pkg/analyzer/test/src/summary/expr_builder_test.dart
@@ -23,7 +23,10 @@
 import 'test_strategies.dart';
 
 main() {
-  if (AnalysisDriver.useSummary2) return;
+  if (AnalysisDriver.useSummary2) {
+    test('fake', () {});
+    return;
+  }
   defineReflectiveSuite(() {
     defineReflectiveTests(ExprBuilderTest);
     defineReflectiveTests(ExprBuilderWithConstantUpdateTest);
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index d3dbb1d..bb34cbd 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -13,7 +13,10 @@
 import 'test_strategies.dart';
 
 main() {
-  if (AnalysisDriver.useSummary2) return;
+  if (AnalysisDriver.useSummary2) {
+    test('fake', () {});
+    return;
+  }
   defineReflectiveSuite(() {
     defineReflectiveTests(LinkerUnitTest);
   });
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
index 6e932bd..aa47aaaa 100644
--- a/pkg/analyzer/test/src/summary/prelinker_test.dart
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -3,13 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'summary_common.dart';
 import 'test_strategies.dart';
 
 main() {
-  if (AnalysisDriver.useSummary2) return;
+  if (AnalysisDriver.useSummary2) {
+    test('fake', () {});
+    return;
+  }
   defineReflectiveSuite(() {
     defineReflectiveTests(PrelinkerTest);
   });
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 3ab3089..6785245 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -7,10 +7,10 @@
 import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:analyzer/src/summary2/informative_data.dart';
 import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/linked_bundle_context.dart';
@@ -124,9 +124,7 @@
     if (analysisContext.typeProvider == null) {
       var dartCore = elementFactory.libraryOfUri('dart:core');
       var dartAsync = elementFactory.libraryOfUri('dart:async');
-      var typeProvider = SummaryTypeProvider()
-        ..initializeCore(dartCore)
-        ..initializeAsync(dartAsync);
+      var typeProvider = TypeProviderImpl(dartCore, dartAsync);
       analysisContext.typeProvider = typeProvider;
 
       dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 3f66e12..190954b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'element_text.dart';
@@ -10,7 +11,10 @@
 import 'test_strategies.dart';
 
 main() {
-  if (AnalysisDriver.useSummary2) return;
+  if (AnalysisDriver.useSummary2) {
+    test('fake', () {});
+    return;
+  }
   defineReflectiveSuite(() {
     defineReflectiveTests(ApplyCheckElementTextReplacements);
     defineReflectiveTests(ResynthesizeAstStrongTest);
@@ -27,6 +31,13 @@
 @reflectiveTest
 class ResynthesizeAstStrongTest extends ResynthesizeTestStrategyTwoPhase
     with ResynthesizeTestCases, GetElementTestCases, ResynthesizeTestHelpers {
+  @override
+  @failingTest
+  test_class_constructor_field_formal_functionTyped_withReturnType_generic() async {
+    await super
+        .test_class_constructor_field_formal_functionTyped_withReturnType_generic();
+  }
+
   @failingTest // See dartbug.com/32290
   test_const_constructor_inferred_args() =>
       super.test_const_constructor_inferred_args();
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 8745996..38ce11b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -632,6 +632,21 @@
 ''');
   }
 
+  test_class_constructor_field_formal_functionTyped_withReturnType_generic() async {
+    var library = await checkLibrary(r'''
+class C {
+  Function() f;
+  C(List<U> this.f<T, U>(T t));
+}
+''');
+    checkElementText(library, r'''
+class C {
+  dynamic Function() f;
+  C(List<U> Function<T, U>(T) this.f/*(T t)*/);
+}
+''');
+  }
+
   test_class_constructor_field_formal_multiple_matching_fields() async {
     // This is a compile-time error but it should still analyze consistently.
     var library = await checkLibrary('class C { C(this.x); int x; String x; }',
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
index 3911aab..c6d4b8d 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
@@ -3,13 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'summary_common.dart';
 import 'test_strategies.dart';
 
 main() {
-  if (AnalysisDriver.useSummary2) return;
+  if (AnalysisDriver.useSummary2) {
+    test('fake', () {});
+    return;
+  }
   defineReflectiveSuite(() {
     defineReflectiveTests(LinkedSummarizeAstStrongTest);
   });
diff --git a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
index 7ff704f..43a4011 100644
--- a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
+++ b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
@@ -5,10 +5,10 @@
 import 'dart:io';
 
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:test/test.dart';
 
 import '../dart/ast/parse_base.dart';
+import '../../utils/package_root.dart' as package_root;
 import 'ast_text_printer_test.dart';
 
 main() {
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 764e8b1..0c311e0 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -186,6 +186,14 @@
         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);
@@ -233,6 +241,7 @@
         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');
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d8e26ac..7360730 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -1972,10 +1972,10 @@
   // resolving these shouldn't crash.
   foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
   x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3');
-  foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
-  x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1');
+  foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/(1);
+  x = foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/('1');
   x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/2, 3);
-  x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1);
+  x = foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1);
 
   // named arguments
   bar(y: 1, x: 2, /*error:UNDEFINED_NAMED_PARAMETER*/z: 3);
@@ -2037,12 +2037,12 @@
 
   test_genericMethodSuperSubstitute() async {
     await checkFile(r'''
-class Clonable<T> {}
+class Cloneable<T> {}
 class G<T> {
-  create<A extends Clonable<T>, B extends Iterable<A>>() => null;
+  create<A extends Cloneable<T>, B extends Iterable<A>>() => null;
 }
 class H extends G<num> {
-  create2() => super.create<Clonable<int>, List<Clonable<int>>>();
+  create2() => super.create<Cloneable<int>, List<Cloneable<int>>>();
 }
     ''');
   }
@@ -4899,18 +4899,18 @@
   if (object is int) print(object.isEven);
   if (object is String) print(/*info:DYNAMIC_INVOKE*/object./*error:UNDEFINED_METHOD*/substring(1));
 }
-class Clonable<T> {}
-class SubClonable<T> extends Clonable<T> {
+class Cloneable<T> {}
+class SubCloneable<T> extends Cloneable<T> {
   T m(T t) => t;
 }
-void takesSubClonable<A>(SubClonable<A> t) {}
+void takesSubCloneable<A>(SubCloneable<A> t) {}
 
-void h<T extends Clonable<T>>(T object) {
-  if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubClonable<T>) {
+void h<T extends Cloneable<T>>(T object) {
+  if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubCloneable<T>) {
     print(object.m(object));
 
-    SubClonable<T> s = object;
-    takesSubClonable<T>(object);
+    SubCloneable<T> s = object;
+    takesSubCloneable<T>(object);
     // Issue #35799: According to the language team, this should work, but both
     // analyzer and CFE currently reject it, likely due to a strange
     // representation of promoted type variables.
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index a3a31c2..94feba2 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -488,9 +488,9 @@
         'error:TYPE_ARGUMENT_NOT_MATCHING_BOUNDS';
 //    if (hasExtraTaskModelPass) errors = '$errors,$errors';
     var unit = await checkFile('''
-class Clonable<T> {}
+class Cloneable<T> {}
 
-class Pair<T extends Clonable<T>, U extends Clonable<U>> {
+class Pair<T extends Cloneable<T>, U extends Cloneable<U>> {
   T t;
   U u;
   Pair(this.t, this.u);
@@ -503,7 +503,7 @@
 }
 ''');
     var x = findLocalVariable(unit, 'x');
-    expect(x.type.toString(), 'Pair<Clonable<dynamic>, Clonable<dynamic>>');
+    expect(x.type.toString(), 'Pair<Cloneable<dynamic>, Cloneable<dynamic>>');
   }
 
   test_constructors_inferFromArguments() async {
@@ -524,7 +524,7 @@
   C<num> c_num2 = (/*info:INFERRED_TYPE_ALLOCATION*/new C(456))
       ..t = 1.0;
 
-  // Down't infer from explicit dynamic.
+  // Don't infer from explicit dynamic.
   var c_dynamic = new C<dynamic>(42);
   x.t = /*error:INVALID_ASSIGNMENT*/'hello';
 }
@@ -2488,7 +2488,7 @@
 ''');
   }
 
-  test_inferedType_usesSyntheticFunctionType() async {
+  test_inferredType_usesSyntheticFunctionType() async {
     var mainUnit = await checkFileElement('''
 int f() => null;
 String g() => null;
@@ -2498,7 +2498,7 @@
     expect(v.type.toString(), 'List<Object Function()>');
   }
 
-  test_inferedType_usesSyntheticFunctionType_functionTypedParam() async {
+  test_inferredType_usesSyntheticFunctionType_functionTypedParam() async {
     var mainUnit = await checkFileElement('''
 int f(int x(String y)) => null;
 String g(int x(String y)) => null;
@@ -2508,7 +2508,7 @@
     expect(v.type.toString(), 'List<Object Function(int Function(String))>');
   }
 
-  test_inferedType_usesSyntheticFunctionType_namedParam() async {
+  test_inferredType_usesSyntheticFunctionType_namedParam() async {
     var mainUnit = await checkFileElement('''
 int f({int x}) => null;
 String g({int x}) => null;
@@ -2518,7 +2518,7 @@
     expect(v.type.toString(), 'List<Object Function({x: int})>');
   }
 
-  test_inferedType_usesSyntheticFunctionType_positionalParam() async {
+  test_inferredType_usesSyntheticFunctionType_positionalParam() async {
     var mainUnit = await checkFileElement('''
 int f([int x]) => null;
 String g([int x]) => null;
@@ -2528,7 +2528,7 @@
     expect(v.type.toString(), 'List<Object Function([int])>');
   }
 
-  test_inferedType_usesSyntheticFunctionType_requiredParam() async {
+  test_inferredType_usesSyntheticFunctionType_requiredParam() async {
     var mainUnit = await checkFileElement('''
 int f(int x) => null;
 String g(int x) => null;
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 8fb7e6f..2edf77f 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -8,7 +8,6 @@
 import 'dart:collection';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
@@ -172,14 +171,13 @@
     Map<List<_ErrorExpectation>, List<AnalysisError>> different) {
   // Get the source code. This reads the data again, but it's safe because
   // all tests use memory file system.
-  var sourceCode =
-      resolutionMap.elementDeclaredByCompilationUnit(unit).source.contents.data;
+  var sourceCode = unit.declaredElement.source.contents.data;
 
   String formatActualError(AnalysisError error) {
     int offset = error.offset;
     int length = error.length;
-    var span = _createSpanHelper(unit.lineInfo, offset,
-        resolutionMap.elementDeclaredByCompilationUnit(unit).source, sourceCode,
+    var span = _createSpanHelper(
+        unit.lineInfo, offset, unit.declaredElement.source, sourceCode,
         end: offset + length);
     var levelName = _errorSeverity(analysisOptions, error).displayName;
     return '@$offset $levelName:${error.errorCode.name}\n' +
@@ -192,10 +190,7 @@
     var result = '@$offset $severity:${error.typeName}';
     if (!showSource) return result;
     var span = _createSpanHelper(
-        unit.lineInfo,
-        offset,
-        resolutionMap.elementDeclaredByCompilationUnit(unit).source,
-        sourceCode);
+        unit.lineInfo, offset, unit.declaredElement.source, sourceCode);
     return '$result\n${span.message('')}';
   }
 
@@ -337,8 +332,7 @@
 
     // Extract expectations from the comments in the test files, and
     // check that all errors we emit are included in the expected map.
-    LibraryElement mainLibrary =
-        resolutionMap.elementDeclaredByCompilationUnit(mainUnit).library;
+    LibraryElement mainLibrary = mainUnit.declaredElement.library;
     Set<LibraryElement> allLibraries = _reachableLibraries(mainLibrary);
 
     for (LibraryElement library in allLibraries) {
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index 37bc80a..9681e6c 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
@@ -70,7 +69,7 @@
         return unitMember;
       }
     }
-    Source source = resolutionMap.elementDeclaredByCompilationUnit(unit).source;
+    Source source = unit.declaredElement.source;
     fail('No class named $className in $source');
   }
 
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analyzer/test/utils/package_root.dart
similarity index 100%
rename from pkg/front_end/lib/src/testing/package_root.dart
rename to pkg/analyzer/test/utils/package_root.dart
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 8a6a460..b8ce223 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -9,12 +9,12 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart';
 import 'package:test/test.dart';
 
 import '../tool/diagnostics/generate.dart';
 import 'src/dart/resolution/driver_resolution.dart';
+import 'utils/package_root.dart' as package_root;
 
 /// Validate the documentation associated with the declarations of the error
 /// codes.
diff --git a/pkg/analyzer/test/verify_docs_test.dart b/pkg/analyzer/test/verify_docs_test.dart
index 22c3858..09c9b4f 100644
--- a/pkg/analyzer/test/verify_docs_test.dart
+++ b/pkg/analyzer/test/verify_docs_test.dart
@@ -12,9 +12,10 @@
 import 'package:analyzer/file_system/overlay_file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:test/test.dart';
 
+import 'utils/package_root.dart' as package_root;
+
 main() async {
   SnippetTester tester = SnippetTester();
   await tester.verify();
diff --git a/pkg/analyzer/test/verify_tests_test.dart b/pkg/analyzer/test/verify_tests_test.dart
index e14d258..dc8285b 100644
--- a/pkg/analyzer/test/verify_tests_test.dart
+++ b/pkg/analyzer/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
+import 'utils/package_root.dart' as package_root;
+
 main() {
   PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
   String packageRoot = provider.pathContext.normalize(package_root.packageRoot);
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index a8b6cde..aa77a12 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -23,8 +23,8 @@
 region is required to be a constant. The following locations are constant
 contexts:
 
-* Everything inside a list, map or set literal that's prefixed by the keyword
-  `const`. Example:
+* Everything inside a list, map or set literal that's prefixed by the
+  `const` keyword. Example:
 
   ```dart
   var l = const [/*constant context*/];
@@ -36,7 +36,7 @@
   var p = const Point(/*constant context*/);
   ```
 
-* The initializer for a variable that's prefixed by the keyword `const`.
+* The initializer for a variable that's prefixed by the `const` keyword.
   Example:
 
   ```dart
@@ -432,6 +432,7 @@
 
 {% prettify dart %}
 typedef Binary = int Function(int, int);
+
 int f() {
   return [!Binary!](1, 2);
 }
@@ -477,8 +478,8 @@
 
 The analyzer produces this diagnostic when an element in a constant list
 literal isn't a constant value. The list literal can be constant either
-explicitly (because it's prefixed by the keyword `const`) or implicitly
-(because it appears in a <a href=”#constant-context”>constant context</a>).
+explicitly (because it's prefixed by the `const` keyword) or implicitly
+(because it appears in a [constant context](#constant-context)).
 
 #### Example
 
@@ -493,8 +494,8 @@
 #### Common fixes
 
 If the list needs to be a constant list, then convert the element to be a
-constant. In the example above, you might add the keyword `const`
-to the declaration of `x`:
+constant. In the example above, you might add the `const` keyword to the
+declaration of `x`:
 
 {% prettify dart %}
 const int x = 2;
@@ -609,6 +610,7 @@
 
 {% prettify dart %}
 C f() {}
+
 class C {
   factory C() = [!f!];
 }
@@ -627,6 +629,7 @@
 
 {% prettify dart %}
 C f() {}
+
 class C {
   factory C() => f();
 }
@@ -692,6 +695,7 @@
 
 {% prettify dart %}
 class A<E extends num> {}
+
 var a = A<[!String!]>();
 {% endprettify %}
 
@@ -701,6 +705,7 @@
 
 {% prettify dart %}
 class A<E extends num> {}
+
 var a = A<int>();
 {% endprettify %}
 
@@ -720,6 +725,7 @@
 
 {% prettify dart %}
 class Point {}
+
 void main() {
   [!Piont!] p;
 }
@@ -733,6 +739,7 @@
 
 {% prettify dart %}
 class Point {}
+
 void main() {
   Point p;
 }
@@ -757,6 +764,7 @@
 
 {% prettify dart %}
 List<int> empty() => [];
+
 void main() {
   print([!emty!]());
 }
@@ -770,6 +778,7 @@
 
 {% prettify dart %}
 List<int> empty() => [];
+
 void main() {
   print(empty());
 }
@@ -793,12 +802,7 @@
 The following code produces this diagnostic:
 
 {% prettify dart %}
-class Point {
-  final int x;
-  final int y;
-  Point(this.x, this.y);
-  operator +(Point other) => Point(x + other.x, y + other.[!z!]);
-}
+int f(String s) => s.[!len!];
 {% endprettify %}
 
 #### Common fix
@@ -808,12 +812,7 @@
 fixing the spelling of the getter:
 
 {% prettify dart %}
-class Point {
-  final int x;
-  final int y;
-  Point(this.x, this.y);
-  operator +(Point other) => Point(x + other.x, y + other.y);
-}
+int f(String s) => s.length;
 {% endprettify %}
 
 ### undefined_identifier
@@ -893,6 +892,7 @@
 class C {
   m({int b}) {}
 }
+
 void f(C c) {
   c.m([!a!]: 1);
 }
@@ -907,6 +907,7 @@
 class C {
   m({int b}) {}
 }
+
 void f(C c) {
   c.m(b: 1);
 }
@@ -919,9 +920,11 @@
 class C {
   m({int b}) {}
 }
+
 class D extends C {
   m({int a, int b}) {}
 }
+
 void f(C c) {
   (c as D).m(a: 1);
 }
@@ -933,6 +936,7 @@
 class C {
   m({int a, int b}) {}
 }
+
 void f(C c) {
   c.m(a: 1);
 }
@@ -1049,8 +1053,7 @@
 {% prettify dart %}
 import [!'dart:async'!];
 
-void main() {
-}
+void main() {}
 {% endprettify %}
 
 #### Common fixes
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index 0c7efa6..36b166e 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -10,9 +10,10 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/src/context.dart';
 
+import '../../test/utils/package_root.dart' as package_root;
+
 /// Generate the file `diagnostics.md` based on the documentation associated
 /// with the declarations of the error codes.
 void main() async {
@@ -212,8 +213,8 @@
 region is required to be a constant. The following locations are constant
 contexts:
 
-* Everything inside a list, map or set literal that's prefixed by the keyword
-  `const`. Example:
+* Everything inside a list, map or set literal that's prefixed by the
+  `const` keyword. Example:
 
   ```dart
   var l = const [/*constant context*/];
@@ -225,7 +226,7 @@
   var p = const Point(/*constant context*/);
   ```
 
-* The initializer for a variable that's prefixed by the keyword `const`.
+* The initializer for a variable that's prefixed by the `const` keyword.
   Example:
 
   ```dart
diff --git a/pkg/analyzer/tool/experiments/generate.dart b/pkg/analyzer/tool/experiments/generate.dart
index 6527331..4846520 100644
--- a/pkg/analyzer/tool/experiments/generate.dart
+++ b/pkg/analyzer/tool/experiments/generate.dart
@@ -6,10 +6,11 @@
 
 import 'package:analysis_tool/tools.dart';
 import 'package:front_end/src/fasta/scanner/characters.dart' show $MINUS, $_;
-import 'package:front_end/src/testing/package_root.dart' as pkgRoot;
 import 'package:path/path.dart';
 import 'package:yaml/yaml.dart' show YamlMap, loadYaml;
 
+import '../../test/utils/package_root.dart' as pkgRoot;
+
 main() async {
   await GeneratedContent.generateAll(
       normalize(join(pkgRoot.packageRoot, 'analyzer')), allTargets);
diff --git a/pkg/analyzer/tool/messages/generate.dart b/pkg/analyzer/tool/messages/generate.dart
index babac722..e35adc8 100644
--- a/pkg/analyzer/tool/messages/generate.dart
+++ b/pkg/analyzer/tool/messages/generate.dart
@@ -17,11 +17,12 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analysis_tool/tools.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
-import 'package:front_end/src/testing/package_root.dart' as pkgRoot;
 import 'package:front_end/src/fasta/scanner.dart';
 import 'package:path/path.dart';
 import 'package:yaml/yaml.dart' show loadYaml;
 
+import '../../test/utils/package_root.dart' as pkgRoot;
+
 main() async {
   String analyzerPkgPath = normalize(join(pkgRoot.packageRoot, 'analyzer'));
   String frontEndPkgPath = normalize(join(pkgRoot.packageRoot, 'front_end'));
diff --git a/pkg/analyzer/tool/summary/check_test.dart b/pkg/analyzer/tool/summary/check_test.dart
index af669fb..6c4e635 100644
--- a/pkg/analyzer/tool/summary/check_test.dart
+++ b/pkg/analyzer/tool/summary/check_test.dart
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_tool/tools.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart';
 
+import '../../test/utils/package_root.dart' as package_root;
 import 'generate.dart';
 
 /**
diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart
index d766655..57c11bd 100644
--- a/pkg/analyzer/tool/summary/mini_ast.dart
+++ b/pkg/analyzer/tool/summary/mini_ast.dart
@@ -216,7 +216,7 @@
 
   @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     debugEvent("ClassOrMixinBody");
     push(popList(memberCount,
         new List<ClassMember>.filled(memberCount, null, growable: true)));
@@ -280,9 +280,9 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    debugEvent("FactoryMethod");
+    debugEvent("ClassFactoryMethod");
     pop(); // Body
     pop(); // Type variables
     String name = pop();
@@ -400,7 +400,7 @@
         NullValue.Metadata);
   }
 
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     debugEvent("Method");
     pop(); // Body
diff --git a/pkg/analyzer_cli/lib/src/perf_report.dart b/pkg/analyzer_cli/lib/src/perf_report.dart
index 0463ddd..11178eb 100644
--- a/pkg/analyzer_cli/lib/src/perf_report.dart
+++ b/pkg/analyzer_cli/lib/src/perf_report.dart
@@ -7,7 +7,6 @@
 
 import 'package:analyzer/src/generated/utilities_general.dart'
     show PerformanceTag;
-import 'package:analyzer/src/task/api/model.dart' show AnalysisTask;
 import 'package:analyzer_cli/src/error_formatter.dart';
 import 'package:analyzer_cli/src/options.dart' show CommandLineOptions;
 
@@ -60,39 +59,16 @@
   }
   perfTagsJson['other'] = otherTime;
 
-  // Generate task table.
-  var taskRows = <_TaskRow>[];
-  int totalTaskTime = 0;
-  for (var key in AnalysisTask.stopwatchMap.keys) {
-    var time = AnalysisTask.stopwatchMap[key].elapsedMilliseconds;
-    if (time == 0) continue;
-    totalTaskTime += time;
-    var count = AnalysisTask.countMap[key];
-    taskRows.add(new _TaskRow(key.toString(), time, count));
-  }
-  taskRows.sort((a, b) => b.time.compareTo(a.time));
-
   var reportJson = <String, dynamic>{
     'perfReportVersion': 0,
     'platform': platformJson,
     'options': optionsJson,
     'totalElapsedTime': totalTime,
-    'totalTaskTime': totalTaskTime,
     'analyzedFiles': analyzedFileCount,
     'generatedDiagnostics': stats.unfilteredCount,
     'reportedDiagnostics': stats.filteredCount,
     'performanceTags': perfTagsJson,
-    'tasks': taskRows.map((r) => r.toJson()).toList(),
   };
 
   return _JSON.convert(reportJson);
 }
-
-class _TaskRow {
-  final String name;
-  final int time;
-  final int count;
-  _TaskRow(this.name, this.time, this.count);
-
-  Map toJson() => <String, dynamic>{'name': name, 'time': time, 'count': count};
-}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 52a0e77..6e1993b 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -684,6 +684,41 @@
   }
 
   @override
+  void writeSetterDeclaration(String name,
+      {void bodyWriter(),
+      bool isStatic: false,
+      String nameGroupName,
+      DartType parameterType,
+      String parameterTypeGroupName}) {
+    if (isStatic) {
+      write(Keyword.STATIC.lexeme);
+      write(' ');
+    }
+    write(Keyword.SET.lexeme);
+    write(' ');
+    if (nameGroupName != null) {
+      addSimpleLinkedEdit(nameGroupName, name);
+    } else {
+      write(name);
+    }
+    write('(');
+    if (parameterType != null && !parameterType.isDynamic) {
+      if (writeType(parameterType, groupName: parameterTypeGroupName)) {
+        write(' ');
+      }
+    }
+    // TODO(brianwilkerson) The name of the setter is unlikely to be a good name
+    //  for the parameter. We need to find a better name to produce here.
+    write(name);
+    write(') ');
+    if (bodyWriter == null) {
+      write('{}');
+    } else {
+      bodyWriter();
+    }
+  }
+
+  @override
   bool writeType(DartType type,
       {bool addSupertypeProposals: false,
       String groupName,
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index 6f1d86c..7780d46 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -266,6 +266,24 @@
   void writeReference(Element element);
 
   /**
+   * Write the code for a declaration of a setter with the given [name]. If a
+   * [bodyWriter] is provided, it will be invoked to write the body of the
+   * setter. (The space between the name and the body will automatically be
+   * written.) If [isStatic] is `true`, then the declaration will be preceded
+   * by the `static` keyword. If a [nameGroupName] is provided, the name of the
+   * getter will be included in the linked edit group with that name. If a
+   * [parameterType] is provided, then it will be used as the type of the
+   * parameter. If a [parameterTypeGroupName] is provided, then if a parameter
+   * type was written it will be in the linked edit group with that name.
+   */
+  void writeSetterDeclaration(String name,
+      {void bodyWriter(),
+      bool isStatic: false,
+      String nameGroupName,
+      DartType parameterType,
+      String parameterTypeGroupName});
+
+  /**
    * Write the code for a type annotation for the given [type]. If the [type] is
    * either `null` or represents the type 'dynamic', then the behavior depends
    * on whether a type is [required]. If [required] is `true`, then 'var' will
diff --git a/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart b/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
index e3567fc..41d5c6a 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -55,8 +54,8 @@
       return;
     }
     containingLibrary = request.result.libraryElement;
-    _computeSuggestionsForClass2(collector, target,
-        resolutionMap.elementDeclaredByClassDeclaration(classDecl), optype);
+    _computeSuggestionsForClass2(
+        collector, target, classDecl.declaredElement, optype);
   }
 
   /**
@@ -85,7 +84,7 @@
       if (classDecl == null || classDecl.declaredElement == null) {
         return;
       }
-      classElement = resolutionMap.elementDeclaredByClassDeclaration(classDecl);
+      classElement = classDecl.declaredElement;
     }
     containingLibrary = request.result.libraryElement;
     _computeSuggestionsForClass2(collector, target, classElement, optype,
diff --git a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
index cf2b96f..9fcbad9 100644
--- a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
@@ -62,7 +62,7 @@
             return;
           }
         }
-        fail('No occurence named $elementName');
+        fail('No occurrence named $elementName');
       }
 
       validate('method', [10, 30]);
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index abf151b..a0bfa57 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -6,14 +6,13 @@
 
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/test_utilities/find_node.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -914,8 +913,8 @@
     CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
     FormalParameterList parameters = f.functionExpression.parameters;
-    Iterable<ParameterElement> elements = parameters.parameters
-        .map(resolutionMap.elementDeclaredByFormalParameter);
+    Iterable<ParameterElement> elements =
+        parameters.parameters.map((p) => p.declaredElement);
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -935,8 +934,8 @@
     CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
     FormalParameterList parameters = f.functionExpression.parameters;
-    Iterable<ParameterElement> elements = parameters.parameters
-        .map(resolutionMap.elementDeclaredByFormalParameter);
+    Iterable<ParameterElement> elements =
+        parameters.parameters.map((p) => p.declaredElement);
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -956,8 +955,8 @@
     CompilationUnit unit = (await driver.getResult(path))?.unit;
     FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
     FormalParameterList parameters = f.functionExpression.parameters;
-    Iterable<ParameterElement> elements = parameters.parameters
-        .map(resolutionMap.elementDeclaredByFormalParameter);
+    Iterable<ParameterElement> elements =
+        parameters.parameters.map((p) => p.declaredElement);
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -1112,6 +1111,91 @@
     expect(edits[1].replacement, equalsIgnoringWhitespace('a'));
   }
 
+  test_writeSetterDeclaration_bodyWriter() async {
+    String path = convertPath('/home/test/lib/test.dart');
+    String content = 'class A {}';
+    addSource(path, content);
+
+    DartChangeBuilderImpl builder = newBuilder();
+    await builder.addFileEdit(path, (FileEditBuilder builder) {
+      builder.addInsertion(content.length - 1, (EditBuilder builder) {
+        (builder as DartEditBuilder).writeSetterDeclaration('s',
+            bodyWriter: () {
+          builder.write('{/* TODO */}');
+        });
+      });
+    });
+    SourceEdit edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('set s(s) {/* TODO */}'));
+  }
+
+  test_writeSetterDeclaration_isStatic() async {
+    String path = convertPath('/home/test/lib/test.dart');
+    String content = 'class A {}';
+    addSource(path, content);
+
+    DartChangeBuilderImpl builder = newBuilder();
+    await builder.addFileEdit(path, (FileEditBuilder builder) {
+      builder.addInsertion(content.length - 1, (EditBuilder builder) {
+        (builder as DartEditBuilder)
+            .writeSetterDeclaration('s', isStatic: true);
+      });
+    });
+    SourceEdit edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('static set s(s) {}'));
+  }
+
+  test_writeSetterDeclaration_nameGroupName() async {
+    String path = convertPath('/home/test/lib/test.dart');
+    String content = 'class A {}';
+    addSource(path, content);
+
+    DartChangeBuilderImpl builder = newBuilder();
+    await builder.addFileEdit(path, (FileEditBuilder builder) {
+      builder.addInsertion(content.length - 1, (EditBuilder builder) {
+        (builder as DartEditBuilder)
+            .writeSetterDeclaration('s', nameGroupName: 'name');
+      });
+    });
+    SourceEdit edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('set s(s) {}'));
+
+    List<LinkedEditGroup> linkedEditGroups =
+        builder.sourceChange.linkedEditGroups;
+    expect(linkedEditGroups, hasLength(1));
+    LinkedEditGroup group = linkedEditGroups[0];
+    expect(group.length, 1);
+    expect(group.positions, hasLength(1));
+    Position position = group.positions[0];
+    expect(position.offset, equals(13));
+  }
+
+  test_writeSetterDeclaration_parameterType() async {
+    String path = convertPath('/home/test/lib/test.dart');
+    String content = 'class A {} class B {}';
+    addSource(path, content);
+    DartType typeA = await _getType(path, 'A');
+
+    DartChangeBuilderImpl builder = newBuilder();
+    await builder.addFileEdit(path, (FileEditBuilder builder) {
+      builder.addInsertion(content.length - 1, (EditBuilder builder) {
+        (builder as DartEditBuilder).writeSetterDeclaration('s',
+            parameterType: typeA, parameterTypeGroupName: 'returnType');
+      });
+    });
+    SourceEdit edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('set s(A s) {}'));
+
+    List<LinkedEditGroup> linkedEditGroups =
+        builder.sourceChange.linkedEditGroups;
+    expect(linkedEditGroups, hasLength(1));
+    LinkedEditGroup group = linkedEditGroups[0];
+    expect(group.length, 1);
+    expect(group.positions, hasLength(1));
+    Position position = group.positions[0];
+    expect(position.offset, equals(26));
+  }
+
   test_writeType_dynamic() async {
     String path = convertPath('/home/test/lib/test.dart');
     String content = 'class A {}';
@@ -1121,11 +1205,8 @@
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(resolutionMap
-            .elementDeclaredByCompilationUnit(unit)
-            .context
-            .typeProvider
-            .dynamicType);
+        var typeProvider = unit.declaredElement.context.typeProvider;
+        (builder as DartEditBuilder).writeType(typeProvider.dynamicType);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -1332,13 +1413,9 @@
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
       builder.addInsertion(content.length - 1, (EditBuilder builder) {
-        (builder as DartEditBuilder).writeType(
-            resolutionMap
-                .elementDeclaredByCompilationUnit(unit)
-                .context
-                .typeProvider
-                .dynamicType,
-            required: true);
+        var typeProvider = unit.declaredElement.context.typeProvider;
+        (builder as DartEditBuilder)
+            .writeType(typeProvider.dynamicType, required: true);
       });
     });
     SourceEdit edit = getEdit(builder);
@@ -1503,25 +1580,18 @@
 @reflectiveTest
 class DartFileEditBuilderImplTest extends AbstractContextTest
     with DartChangeBuilderMixin {
-  TypeProvider get typeProvider {
-    return new TestTypeProvider(null, driver);
-  }
-
   test_convertFunctionFromSyncToAsync_closure() async {
     String path = convertPath('/home/test/lib/test.dart');
     addSource(path, '''var f = () {}''');
 
-    CompilationUnit unit = (await driver.getResult(path))?.unit;
-    TopLevelVariableDeclaration variable =
-        unit.declarations[0] as TopLevelVariableDeclaration;
-    FunctionBody body =
-        (variable.variables.variables[0].initializer as FunctionExpression)
-            .body;
+    var resolvedUnit = await driver.getResult(path);
+    var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+    var body = findNode.functionBody('{}');
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
       (builder as DartFileEditBuilder)
-          .convertFunctionFromSyncToAsync(body, typeProvider);
+          .convertFunctionFromSyncToAsync(body, resolvedUnit.typeProvider);
     });
     List<SourceEdit> edits = getEdits(builder);
     expect(edits, hasLength(1));
@@ -1532,14 +1602,14 @@
     String path = convertPath('/home/test/lib/test.dart');
     addSource(path, 'String f() {}');
 
-    CompilationUnit unit = (await driver.getResult(path))?.unit;
-    FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
-    FunctionBody body = function.functionExpression.body;
+    var resolvedUnit = await driver.getResult(path);
+    var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+    var body = findNode.functionBody('{}');
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
       (builder as DartFileEditBuilder)
-          .convertFunctionFromSyncToAsync(body, typeProvider);
+          .convertFunctionFromSyncToAsync(body, resolvedUnit.typeProvider);
     });
     List<SourceEdit> edits = getEdits(builder);
     expect(edits, hasLength(2));
@@ -1663,14 +1733,14 @@
     String path = convertPath('/home/test/lib/test.dart');
     addSource(path, 'String f() {}');
 
-    CompilationUnit unit = (await driver.getResult(path))?.unit;
-    FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
-    TypeAnnotation type = function.returnType;
+    var resolvedUnit = await driver.getResult(path);
+    var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+    var type = findNode.typeAnnotation('String');
 
     DartChangeBuilderImpl builder = newBuilder();
     await builder.addFileEdit(path, (FileEditBuilder builder) {
       (builder as DartFileEditBuilder)
-          .replaceTypeWithFuture(type, typeProvider);
+          .replaceTypeWithFuture(type, resolvedUnit.typeProvider);
     });
     List<SourceEdit> edits = getEdits(builder);
     expect(edits, hasLength(1));
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analyzer_plugin/test/utils/package_root.dart
similarity index 100%
copy from pkg/front_end/lib/src/testing/package_root.dart
copy to pkg/analyzer_plugin/test/utils/package_root.dart
diff --git a/pkg/analyzer_plugin/test/verify_tests_test.dart b/pkg/analyzer_plugin/test/verify_tests_test.dart
index 4aa0876..90f2856 100644
--- a/pkg/analyzer_plugin/test/verify_tests_test.dart
+++ b/pkg/analyzer_plugin/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
+import 'utils/package_root.dart' as package_root;
+
 main() {
   PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
   String packageRoot = provider.pathContext.normalize(package_root.packageRoot);
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index d567451..21975bf 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -250,6 +250,9 @@
   static final Uri dart__js_embedded_names =
       new Uri(scheme: 'dart', path: '_js_embedded_names');
 
+  /// The URI for 'dart:js'.
+  static final Uri dart_js = Uri(scheme: 'dart', path: 'js');
+
   /// The URI for 'package:js'.
   static final Uri package_js = new Uri(scheme: 'package', path: 'js/js.dart');
 
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 3dab917..e118229 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -105,6 +105,12 @@
   /// The dart:_internal library.
   LibraryEntity get internalLibrary;
 
+  /// The dart:js library.
+  LibraryEntity get dartJsLibrary;
+
+  /// The package:js library.
+  LibraryEntity get packageJsLibrary;
+
   /// The `NativeTypedData` class from dart:typed_data.
   ClassEntity get typedDataClass;
 
@@ -541,12 +547,14 @@
 
   ClassEntity getDefaultSuperclass(
       ClassEntity cls, NativeBasicData nativeBasicData);
+
+  // From package:js
+  FunctionEntity get jsAllowInterop;
 }
 
 abstract class KCommonElements implements CommonElements {
   // From package:js
   ClassEntity get jsAnnotationClass;
-
   ClassEntity get jsAnonymousClass;
 
   ClassEntity get pragmaClass;
@@ -783,6 +791,16 @@
   LibraryEntity get internalLibrary => _internalLibrary ??=
       _env.lookupLibrary(Uris.dart__internal, required: true);
 
+  LibraryEntity _dartJsLibrary;
+  @override
+  LibraryEntity get dartJsLibrary =>
+      _dartJsLibrary ??= _env.lookupLibrary(Uris.dart_js);
+
+  LibraryEntity _packageJsLibrary;
+  @override
+  LibraryEntity get packageJsLibrary =>
+      _packageJsLibrary ??= _env.lookupLibrary(Uris.package_js);
+
   ClassEntity _typedDataClass;
   @override
   ClassEntity get typedDataClass =>
@@ -1429,28 +1447,22 @@
   ClassEntity get jsConstClass =>
       _jsConstClass ??= _findClass(foreignLibrary, 'JS_CONST');
 
+  // From dart:js
+  FunctionEntity _jsAllowInterop;
+  @override
+  FunctionEntity get jsAllowInterop => _jsAllowInterop ??=
+      _findLibraryMember(dartJsLibrary, 'allowInterop', required: false);
+
   // From package:js
   ClassEntity _jsAnnotationClass;
   @override
-  ClassEntity get jsAnnotationClass {
-    if (_jsAnnotationClass == null) {
-      LibraryEntity library = _env.lookupLibrary(Uris.package_js);
-      if (library == null) return null;
-      _jsAnnotationClass = _findClass(library, 'JS');
-    }
-    return _jsAnnotationClass;
-  }
+  ClassEntity get jsAnnotationClass => _jsAnnotationClass ??=
+      _findClass(packageJsLibrary, 'JS', required: false);
 
   ClassEntity _jsAnonymousClass;
   @override
-  ClassEntity get jsAnonymousClass {
-    if (_jsAnonymousClass == null) {
-      LibraryEntity library = _env.lookupLibrary(Uris.package_js);
-      if (library == null) return null;
-      _jsAnonymousClass = _findClass(library, '_Anonymous');
-    }
-    return _jsAnonymousClass;
-  }
+  ClassEntity get jsAnonymousClass => _jsAnonymousClass ??=
+      _findClass(packageJsLibrary, '_Anonymous', required: false);
 
   @override
   FunctionEntity findHelperFunction(String name) => _findHelperFunction(name);
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 062985a..69425c5 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -84,7 +84,7 @@
   /// Is `true` if this type is the 'Object' type defined in 'dart:core'.
   bool get isObject => false;
 
-  /// Applies [f] to each occurence of a [TypeVariableType] within this
+  /// Applies [f] to each occurrence of a [TypeVariableType] within this
   /// type. This excludes function type variables, whether free or bound.
   void forEachTypeVariable(f(TypeVariableType variable)) {}
 
diff --git a/pkg/compiler/lib/src/ir/closure.dart b/pkg/compiler/lib/src/ir/closure.dart
index 102ac3e..a1c9773 100644
--- a/pkg/compiler/lib/src/ir/closure.dart
+++ b/pkg/compiler/lib/src/ir/closure.dart
@@ -392,7 +392,7 @@
       this.type, this.context, this.kind, this.typeDeclaration);
 
   @override
-  accept(ir.Visitor v) {
+  R accept<R>(ir.Visitor<R> v) {
     throw new UnsupportedError('TypeVariableTypeWithContext.accept');
   }
 
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index 46f1e9e..958c1ce 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -168,7 +168,7 @@
   }
 
   @override
-  accept(ir.TreeVisitor v) {
+  R accept<R>(ir.TreeVisitor<R> v) {
     throw new UnsupportedError("ConstantReference.accept");
   }
 
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 01cad9d..60e8c84 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -509,7 +509,7 @@
   /// [fn] in that place.
   withExpressions(List<js.Expression> nodes, fn(List<js.Expression> results)) {
     int oldTempVarIndex = currentTempVarIndex;
-    // Find last occurence of a 'transform' expression in [nodes].
+    // Find last occurrence of a 'transform' expression in [nodes].
     // All expressions before that must be stored in temp-vars.
     int lastTransformIndex = 0;
     for (int i = nodes.length - 1; i >= 0; --i) {
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 7742425..c755f95 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -546,6 +546,16 @@
         ], fixed: true));
   }
 
+  BackendImpact _allowInterop;
+
+  BackendImpact get allowInterop => _allowInterop ??= BackendImpact(
+          staticUses: [
+            _commonElements.jsAllowInterop,
+          ],
+          features: EnumSet<BackendFeature>.fromValues([
+            BackendFeature.needToInitializeIsolateAffinityTag,
+          ], fixed: true));
+
   BackendImpact _numClasses;
 
   BackendImpact get numClasses {
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index b944875..8b4374b 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -867,7 +867,10 @@
     // apply. So we can directly grab a name.
     if (element is JSEntity) {
       return _disambiguateInternalMember(
-          element, () => (element as JSEntity).declaredName);
+          element,
+          () => (element as JSEntity)
+              .declaredName
+              .replaceAll(_nonIdentifierRE, '_'));
     }
 
     // If the name of the field might clash with another field,
@@ -1257,7 +1260,7 @@
       ClassEntity enclosingClass = element.enclosingClass;
       return '${enclosingClass.name}_${element.name}';
     }
-    return element.name.replaceAll('+', '_');
+    return element.name.replaceAll(_nonIdentifierRE, '_');
   }
 
   String _proposeNameForLazyStaticGetter(MemberEntity element) {
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index cc517d2..1d7794a 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -46,6 +46,15 @@
   /// Returns `true` if js interop features are used.
   bool get isJsInteropUsed;
 
+  /// Returns `true` if `allowInterop()` is invoked.
+  bool get isAllowInteropUsed;
+
+  /// Marks `allowInterop()` as used.
+  ///
+  /// [isAllowInteropUsed] is initially false on the closed world, and is only
+  /// set during codegen enqueuing.
+  void registerAllowInterop();
+
   /// Returns `true` if [element] is a JsInterop library.
   bool isJsInteropLibrary(LibraryEntity element);
 
@@ -258,6 +267,7 @@
     _closed = true;
     return new NativeBasicDataImpl(
         environment,
+        false,
         nativeClassTagInfo,
         jsInteropLibraries,
         jsInteropClasses,
@@ -277,6 +287,8 @@
 
   final ElementEnvironment _env;
 
+  bool _isAllowInteropUsed;
+
   /// Tag info for native JavaScript classes names. See
   /// [setNativeClassTagInfo].
   final Map<ClassEntity, NativeClassTag> nativeClassTagInfo;
@@ -295,6 +307,7 @@
 
   NativeBasicDataImpl(
       this._env,
+      this._isAllowInteropUsed,
       this.nativeClassTagInfo,
       this.jsInteropLibraries,
       this.jsInteropClasses,
@@ -329,13 +342,20 @@
       jsInteropMembers[map.getMember(node)] = name;
     });
 
-    return new NativeBasicDataImpl(env, nativeClassTagInfo, jsInteropLibraries,
-        jsInteropClasses, anonymousJsInteropClasses, jsInteropMembers);
+    return new NativeBasicDataImpl(
+        env,
+        false,
+        nativeClassTagInfo,
+        jsInteropLibraries,
+        jsInteropClasses,
+        anonymousJsInteropClasses,
+        jsInteropMembers);
   }
 
   factory NativeBasicDataImpl.readFromDataSource(
       DataSource source, ElementEnvironment elementEnvironment) {
     source.begin(tag);
+    bool isAllowInteropUsed = source.readBool();
     Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
         source.readClassMap(() {
       List<String> names = source.readStrings();
@@ -352,6 +372,7 @@
     source.end(tag);
     return new NativeBasicDataImpl(
         elementEnvironment,
+        isAllowInteropUsed,
         nativeClassTagInfo,
         jsInteropLibraries,
         jsInteropClasses,
@@ -362,6 +383,7 @@
   @override
   void writeToDataSink(DataSink sink) {
     sink.begin(tag);
+    sink.writeBool(isAllowInteropUsed);
     sink.writeClassMap(nativeClassTagInfo, (NativeClassTag tag) {
       sink.writeStrings(tag.names);
       sink.writeBool(tag.isNonLeaf);
@@ -375,6 +397,14 @@
   }
 
   @override
+  bool get isAllowInteropUsed => _isAllowInteropUsed;
+
+  @override
+  void registerAllowInterop() {
+    _isAllowInteropUsed = true;
+  }
+
+  @override
   bool isNativeClass(ClassEntity element) {
     if (isJsInteropClass(element)) return true;
     return nativeClassTagInfo.containsKey(element);
@@ -622,6 +652,19 @@
   }
 
   @override
+  bool get _isAllowInteropUsed => _nativeBasicData._isAllowInteropUsed;
+
+  @override
+  set _isAllowInteropUsed(bool value) =>
+      _nativeBasicData._isAllowInteropUsed = value;
+
+  @override
+  bool get isAllowInteropUsed => _nativeBasicData.isAllowInteropUsed;
+
+  @override
+  void registerAllowInterop() => _nativeBasicData.registerAllowInterop();
+
+  @override
   Map<LibraryEntity, String> get jsInteropLibraries =>
       _nativeBasicData.jsInteropLibraries;
 
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index a6be0ee..c781753 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -184,6 +184,12 @@
       _backendUsage.isNoSuchMethodUsed = true;
     }
 
+    if (_nativeData.isAllowInteropUsed) {
+      _backendUsage.processBackendImpact(_impacts.allowInterop);
+      enqueuer
+          .applyImpact(_impacts.allowInterop.createImpact(_elementEnvironment));
+    }
+
     if (!enqueuer.queueIsEmpty) return false;
 
     return true;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index e5a9ca3..704c07a 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -254,7 +254,8 @@
     List<Holder> holders = _registry.holders.toList(growable: false);
 
     bool needsNativeSupport =
-        _nativeCodegenEnqueuer.hasInstantiatedNativeClasses;
+        _nativeCodegenEnqueuer.hasInstantiatedNativeClasses ||
+            _nativeData.isAllowInteropUsed;
 
     assert(!needsNativeSupport || nativeClasses.isNotEmpty);
 
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 5aa8407..1bf43b4 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -288,6 +288,7 @@
         map.toBackendMemberMap(nativeBasicData.jsInteropMembers, identity);
     return new NativeBasicDataImpl(
         _elementEnvironment,
+        nativeBasicData.isAllowInteropUsed,
         nativeClassTagInfo,
         jsInteropLibraries,
         jsInteropClasses,
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 4552d00..766bfa0 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -112,6 +112,11 @@
             _dartTypes.isSubtype(type,
                 _elementEnvironment.getRawType(_commonElements.jsArrayClass))) {
           registerInstantiation(type);
+        } else if (_dartTypes.isSubtype(
+            type,
+            _elementEnvironment
+                .getRawType(_commonElements.jsJavaScriptObjectClass))) {
+          matchingClasses.add(type.element);
         }
         // TODO(johnniwinther): Improve spec string precision to handle type
         // arguments and implements relations that preserve generics. Currently
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index c829130..40e7469 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -107,6 +107,7 @@
   Map<fe.ExperimentalFlag, bool> languageExperiments = {};
 
   /// `true` if CFE performs constant evaluation.
+  /// TODO(johnniwinther, sigmund): Remove this and associated dead code.
   bool get useCFEConstants =>
       languageExperiments[fe.ExperimentalFlag.constantUpdate2018];
 
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 7147b77..77b1dac 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2079,6 +2079,10 @@
 
     List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
 
+    if (element == _commonElements.jsAllowInterop) {
+      _nativeData.registerAllowInterop();
+    }
+
     if (element == _commonElements.checkConcurrentModificationError) {
       // Manually inline the [checkConcurrentModificationError] function.  This
       // function is only called from a for-loop update.  Ideally we would just
diff --git a/pkg/dart2native/bin/dart2aot.dart b/pkg/dart2native/bin/dart2aot.dart
new file mode 100644
index 0000000..b406184
--- /dev/null
+++ b/pkg/dart2native/bin/dart2aot.dart
@@ -0,0 +1,81 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'package:args/args.dart';
+import 'package:path/path.dart';
+
+const clearLine = '\r\x1b[2K';
+
+void aot(String sourceFile, String snapshotFile, bool enableAsserts,
+    bool buildElf, bool tfa, bool noTfa, String packages, List<String> ds) {
+  if (!FileSystemEntity.isFileSync(sourceFile)) {
+    print('Error: $sourceFile is not a file');
+    return;
+  }
+
+  String genSnapshotOption = buildElf
+      ? '--snapshot-kind=app-aot-assembly'
+      : '--snapshot-kind=app-aot-blobs';
+  String genSnapshotFilename = buildElf
+      ? '--assembly=$snapshotFile.S'
+      : '--blobs_container_filename=$snapshotFile';
+
+  String snapDir = dirname(Platform.script.path);
+  String binDir = canonicalize(join(snapDir, '..'));
+  String sdkDir = canonicalize(join(binDir, '..'));
+  String dartCommand = join(binDir, 'dart');
+  String snapshot = join(snapDir, 'gen_kernel.dart.snapshot');
+
+  stdout.write('${clearLine}Generating AOT snapshot');
+  List<String> dartArgs = <String>[
+    snapshot,
+    '--platform',
+    '${sdkDir}//lib/_internal/vm_platform_strong.dill',
+    '--aot',
+    '-Ddart.vm.product=true',
+    if (tfa) '--tfa',
+    if (noTfa) '--no-tfa',
+    ...ds,
+    if (packages != null) ...['--packages', packages],
+    '-o',
+    '$snapshotFile.dill',
+    sourceFile
+  ];
+
+  var cmdResult = Process.runSync(dartCommand, dartArgs);
+  if (cmdResult.exitCode != 0) {
+    print('\nGenerating AOT snapshot failed\n');
+    print(cmdResult.stdout);
+    print(cmdResult.stderr);
+    return;
+  }
+
+  stdout.write("${clearLine}Generating AOT .dill");
+  String genSnapshotCommand = join(binDir, 'utils', 'gen_snapshot');
+  List<String> genSnapshotArgs = [
+    genSnapshotOption,
+    genSnapshotFilename,
+    if (enableAsserts) '--enable-asserts',
+    '$snapshotFile.dill'
+  ];
+  cmdResult = Process.runSync(genSnapshotCommand, genSnapshotArgs);
+  if (cmdResult.exitCode != 0) {
+    print('\nGenerating AOT .dill failed\n');
+    print(cmdResult.stdout);
+    print(cmdResult.stderr);
+    return;
+  }
+  stdout.write("${clearLine}Done.\n");
+  stdout.flush();
+}
+
+void setupAOTArgs(ArgParser parser) {
+  parser.addFlag('build-elf');
+  parser.addFlag('enable-asserts');
+  parser.addFlag('tfa');
+  parser.addFlag('no-tfa');
+  parser.addOption('packages');
+}
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
new file mode 100644
index 0000000..ac9cf35
--- /dev/null
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -0,0 +1,70 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:args/args.dart';
+import 'dart2aot.dart';
+
+typedef void Command(ArgResults args, List<String> ds);
+
+void main(List<String> args) {
+  Map<String, Command> commands = <String, Command>{};
+  commands['aot'] = callAOT;
+
+  // Read -D args that the ArgParser can't handle.
+  List<String> ds = [];
+  args = filterDArgs(args, ds);
+
+  ArgParser parser = ArgParser();
+  parser.addFlag('help');
+  ArgParser aotParser = parser.addCommand('aot');
+  setupAOTArgs(aotParser);
+
+  ArgResults result = null;
+  try {
+    result = parser.parse(args);
+  } catch (ArgParserException) {
+    // We handle this case as result == null below.
+  }
+
+  if (result == null || result.command == null || result['help']) {
+    print('dart2native <command> <args>\n');
+    print(' command: ');
+    print('   aot  - Compile script into one ahead of time dart snapshot');
+    return;
+  }
+
+  if (commands.containsKey(result.command.name)) {
+    commands[result.command.name](result.command, ds);
+    return;
+  }
+}
+
+void callAOT(ArgResults args, List<String> ds) {
+  List<String> rest = args.rest;
+  if (rest.length != 2) {
+    print(
+        'Usage: dart2native aot [options] <dart-source-file> <dart-aot-file>\n');
+    print(
+        'Dart AOT (ahead-of-time) compile Dart source code into native machine code.');
+    return;
+  }
+
+  aot(rest[0], rest[1], args['build-elf'], args['enable-asserts'], args['tfa'],
+      args['no-tfa'], args['packages'], ds);
+}
+
+List<String> filterDArgs(List<String> args, List<String> ds) {
+  List<String> result = <String>[];
+
+  args.forEach((String arg) {
+    if (!arg.startsWith('-D')) {
+      result.add(arg);
+    } else {
+      ds.add(arg);
+    }
+  });
+
+  return result;
+}
diff --git a/pkg/dart2native/pubspec.yaml b/pkg/dart2native/pubspec.yaml
new file mode 100644
index 0000000..be267fc
--- /dev/null
+++ b/pkg/dart2native/pubspec.yaml
@@ -0,0 +1,16 @@
+name: dart2native
+version: 0.0.1
+author: Dart Team <misc@dartlang.org>
+homepage: https://github.com/dart-lang/sdk/tree/master/pkg/aot
+
+
+# Add the bin/dart2native.dart script to the scripts pub installs.
+executables:
+  dart2native:
+
+dependencies:
+   args: ^1.4.0
+   path:
+
+dev_dependencies:
+
diff --git a/pkg/dartfix/lib/src/driver.dart b/pkg/dartfix/lib/src/driver.dart
index 3908b60..fa4c91a 100644
--- a/pkg/dartfix/lib/src/driver.dart
+++ b/pkg/dartfix/lib/src/driver.dart
@@ -32,11 +32,10 @@
   Ansi get ansi => logger.ansi;
 
   Future applyFixes() async {
-    showDescriptions('Recommended changes', result.suggestions);
     showDescriptions('Recommended changes that cannot be automatically applied',
         result.otherSuggestions);
     showDetails(result.details);
-    if (result.suggestions.isEmpty) {
+    if (result.edits.isEmpty) {
       logger.stdout('');
       logger.stdout(result.otherSuggestions.isNotEmpty
           ? 'None of the recommended changes can be automatically applied.'
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index f795cfb..6ae1c24 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -300,9 +299,7 @@
     }
     if (compilationUnits.isNotEmpty) {
       _constants = ConstFieldVisitor(types, declaredVariables,
-          dummySource: resolutionMap
-              .elementDeclaredByCompilationUnit(compilationUnits.first)
-              .source);
+          dummySource: compilationUnits.first.declaredElement.source);
     }
 
     // Add implicit dart:core dependency so it is first.
@@ -2618,7 +2615,7 @@
     }
     fn.sourceInformation = _functionEnd(node);
 
-    var element = resolutionMap.elementDeclaredByFunctionDeclaration(node);
+    var element = node.declaredElement;
     var nameExpr = _emitTopLevelName(element);
     body.add(js.statement('# = #', [
       nameExpr,
@@ -3018,7 +3015,7 @@
   /// inferred generic function instantiation.
   js_ast.Expression _emitSimpleIdentifier(SimpleIdentifier node,
       [PrefixedIdentifier prefix]) {
-    var accessor = resolutionMap.staticElementForIdentifier(node);
+    var accessor = node.staticElement;
     if (accessor == null) {
       return _throwUnsafe('unresolved identifier: ' + (node.name ?? '<null>'));
     }
@@ -3529,7 +3526,7 @@
       return _badAssignment("Unimplemented: unknown name '$node'", node, right);
     }
 
-    var accessor = resolutionMap.staticElementForIdentifier(node);
+    var accessor = node.staticElement;
     if (accessor == null) return unimplemented();
 
     // Get the original declaring element. If we had a property accessor, this
@@ -4516,7 +4513,7 @@
 
   @override
   visitInstanceCreationExpression(InstanceCreationExpression node) {
-    var element = resolutionMap.staticElementForConstructorReference(node);
+    var element = node.staticElement;
     var constructor = node.constructorName;
     if (node.isConst &&
         element?.name == 'fromEnvironment' &&
@@ -5840,7 +5837,7 @@
   /// Returns a [js_ast.Expression] for each [CollectionElement] in [nodes].
   ///
   /// Visits all [nodes] in order and nested [CollectionElement]s depth first
-  /// to produce [JS.Expresison]s intended to be used when outputing a
+  /// to produce [JS.Expression]s intended to be used when outputing a
   /// collection literal.
   ///
   /// [IfElement]s and [ForElement]s will be transformed into a spread of a
@@ -6747,9 +6744,8 @@
   var prefix = targetIdentifier.staticElement as PrefixElement;
 
   // The library the prefix is referring to must come from a deferred import.
-  var containingLibrary = resolutionMap
-      .elementDeclaredByCompilationUnit(target.root as CompilationUnit)
-      .library;
+  var containingLibrary =
+      (target.root as CompilationUnit).declaredElement.library;
   var imports = containingLibrary.getImportsWithPrefix(prefix);
   return imports.length == 1 && imports[0].isDeferred;
 }
diff --git a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
index ecb118f..4aa976d 100644
--- a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
@@ -3,12 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
+
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/ast/token.dart' show TokenType;
 import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+
 import 'element_helpers.dart' show getStaticType, isInlineJS, findAnnotation;
 import 'js_interop.dart' show isNotNullAnnotation, isNullCheckAnnotation;
 import 'js_typerep.dart';
@@ -53,7 +54,7 @@
   bool _isNonNullMethodInvocation(MethodInvocation expr) {
     // TODO(vsm): This logic overlaps with the resolver.
     // Where is the best place to put this?
-    var e = resolutionMap.staticElementForIdentifier(expr.methodName);
+    var e = expr.methodName.staticElement;
     if (e == null) return false;
     if (isInlineJS(e)) {
       // Fix types for JS builtin calls.
@@ -220,7 +221,7 @@
       return _isNullable(expr.expression, localIsNullable);
     }
     if (expr is InstanceCreationExpression) {
-      var e = resolutionMap.staticElementForConstructorReference(expr);
+      var e = expr.staticElement;
       if (e == null) return true;
 
       // Follow redirects.
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 6606e51..bf38ecb 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -275,6 +275,11 @@
     doneInputSummaries = List<Component>(summaryModules.length);
     compilerState = await fe.initializeIncrementalCompiler(
         oldCompilerState,
+        {
+          "trackWidgetCreation=$trackWidgetCreation",
+          "multiRootScheme=${fileSystem.markerScheme}",
+          "multiRootRoots=${fileSystem.roots}",
+        },
         doneInputSummaries,
         compileSdk,
         sourcePathToUri(getSdkPath()),
@@ -377,8 +382,7 @@
     outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
   }
 
-  var compiler = ProgramCompiler(
-      component, result.classHierarchy, options, declaredVariables);
+  var compiler = ProgramCompiler(component, result.classHierarchy, options);
 
   var jsModule = compiler.emitModule(
       component, result.inputSummaries, inputSummaries, summaryModules);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 0cd7d86..fd5a3de 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -62,7 +62,7 @@
   /// Let variables collected for the given function.
   List<js_ast.TemporaryId> _letVariables;
 
-  final _constTable = js_ast.TemporaryId("CT");
+  final _constTable = _emitTemporaryId("CT");
 
   // Constant getters used to populate the constant table.
   final _constLazyAccessors = List<js_ast.Method>();
@@ -216,10 +216,10 @@
   final NullableInference _nullableInference;
 
   factory ProgramCompiler(Component component, ClassHierarchy hierarchy,
-      SharedCompilerOptions options, Map<String, String> declaredVariables) {
+      SharedCompilerOptions options) {
     var coreTypes = CoreTypes(component);
     var types = TypeSchemaEnvironment(coreTypes, hierarchy);
-    var constants = DevCompilerConstants(types, declaredVariables);
+    var constants = DevCompilerConstants();
     var nativeTypes = NativeTypeSet(coreTypes, constants);
     var jsTypeRep = JSTypeRep(types, hierarchy);
     return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
@@ -503,6 +503,12 @@
     }
   }
 
+  static js_ast.Identifier _emitIdentifier(String name) =>
+      js_ast.Identifier(escapeIdentifier(name));
+
+  static js_ast.TemporaryId _emitTemporaryId(String name) =>
+      js_ast.TemporaryId(escapeIdentifier(name));
+
   js_ast.Statement _emitClassDeclaration(Class c) {
     // Mixins are unrolled in _defineClass.
     if (c.isAnonymousMixin) return null;
@@ -518,8 +524,8 @@
     // https://github.com/dart-lang/sdk/issues/31003
     var className = c.typeParameters.isNotEmpty
         ? (c == _jsArrayClass
-            ? js_ast.Identifier(c.name)
-            : js_ast.TemporaryId(getLocalClassName(c)))
+            ? _emitIdentifier(c.name)
+            : _emitTemporaryId(getLocalClassName(c)))
         : _emitTopLevelName(c);
 
     var savedClassProperties = _classProperties;
@@ -586,7 +592,7 @@
       jsFormals,
       _typeTable.discharge(formals),
       body,
-      className ?? js_ast.Identifier(name)
+      className ?? _emitIdentifier(name)
     ]);
 
     var genericArgs = [
@@ -610,7 +616,7 @@
           .toStatement();
     }
     var classExpr = js_ast.ClassExpression(
-        js_ast.TemporaryId(getLocalClassName(c)), heritage, methods);
+        _emitTemporaryId(getLocalClassName(c)), heritage, methods);
     return js.statement('# = #;', [className, classExpr]);
   }
 
@@ -651,10 +657,10 @@
     var instanceMethods = methods.where((m) => !m.isStatic).toList();
 
     body.add(_emitClassStatement(c, className, heritage, staticMethods));
-    var superclassId = js_ast.TemporaryId(getLocalClassName(c.superclass));
+    var superclassId = _emitTemporaryId(getLocalClassName(c.superclass));
     var classId = className is js_ast.Identifier
         ? className
-        : js_ast.TemporaryId(getLocalClassName(c));
+        : _emitTemporaryId(getLocalClassName(c));
 
     var mixinMemberClass =
         js_ast.ClassExpression(classId, superclassId, instanceMethods);
@@ -819,7 +825,7 @@
         mixinBody.add(runtimeStatement('applyMixin(#, #)', [
           classExpr,
           js_ast.ClassExpression(
-              js_ast.TemporaryId(getLocalClassName(c)), mixinClass, methods)
+              _emitTemporaryId(getLocalClassName(c)), mixinClass, methods)
         ]));
       }
 
@@ -837,14 +843,14 @@
       var m = mixins[i];
       var mixinName =
           getLocalClassName(superclass) + '_' + getLocalClassName(m.classNode);
-      var mixinId = js_ast.TemporaryId(mixinName + '\$');
+      var mixinId = _emitTemporaryId(mixinName + '\$');
       // Bind the mixin class to a name to workaround a V8 bug with es6 classes
       // and anonymous function names.
       // TODO(leafp:) Eliminate this once the bug is fixed:
       // https://bugs.chromium.org/p/v8/issues/detail?id=7069
       body.add(js.statement("const # = #", [
         mixinId,
-        js_ast.ClassExpression(js_ast.TemporaryId(mixinName), baseClass, [])
+        js_ast.ClassExpression(_emitTemporaryId(mixinName), baseClass, [])
       ]));
 
       emitMixinConstructors(mixinId, m);
@@ -1098,7 +1104,7 @@
     if (isClassSymbol == null) {
       // TODO(jmesserly): we could export these symbols, if we want to mark
       // implemented interfaces for user-defined classes.
-      var id = js_ast.TemporaryId("_is_${getLocalClassName(c)}_default");
+      var id = _emitTemporaryId("_is_${getLocalClassName(c)}_default");
       moduleItems.add(
           js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
       isClassSymbol = id;
@@ -1831,7 +1837,7 @@
         js_ast.Method(
             name,
             js.fun('function(x) { return super.# = #; }',
-                [name, _emitCast(js_ast.Identifier('x'), setterType)]),
+                [name, _emitCast(_emitIdentifier('x'), setterType)]),
             isSetter: true),
         js_ast.Method(name, js.fun('function() { return super.#; }', [name]),
             isGetter: true)
@@ -1852,7 +1858,7 @@
     var positionalParameters = function.positionalParameters;
     for (var i = 0, n = positionalParameters.length; i < n; i++) {
       var param = positionalParameters[i];
-      var jsParam = js_ast.Identifier(param.name);
+      var jsParam = _emitIdentifier(param.name);
       jsParams.add(jsParam);
 
       if (isCovariantParameter(param) &&
@@ -1935,7 +1941,7 @@
     var args =
         field.isFinal ? [js_ast.Super(), name] : [js_ast.This(), virtualField];
 
-    js_ast.Expression value = js_ast.Identifier('value');
+    js_ast.Expression value = _emitIdentifier('value');
     if (!field.isFinal && isCovariantField(field)) {
       value = _emitCast(value, field.type);
     }
@@ -1969,7 +1975,7 @@
 
     // Generate setter
     if (!field.isFinal) {
-      var value = js_ast.TemporaryId('value');
+      var value = _emitTemporaryId('value');
       fn = js_ast.Fun([value], js.block('{ this.# = #; }', [name, value]));
       method = js_ast.Method(_declareMemberName(field), fn, isSetter: true);
       jsMethods.add(method);
@@ -2242,7 +2248,7 @@
         var parts = runtimeName.split('.');
         if (parts.length < 2) return propertyName(runtimeName);
 
-        js_ast.Expression result = js_ast.Identifier(parts[0]);
+        js_ast.Expression result = _emitIdentifier(parts[0]);
         for (int i = 1; i < parts.length; i++) {
           result = js_ast.PropertyAccess(result, propertyName(parts[i]));
         }
@@ -2449,7 +2455,7 @@
 
     var nameExpr = _emitTopLevelName(p);
     body.add(js.statement('# = #',
-        [nameExpr, js_ast.NamedFunction(js_ast.TemporaryId(p.name.name), fn)]));
+        [nameExpr, js_ast.NamedFunction(_emitTemporaryId(p.name.name), fn)]));
     // Function types of top-level/static functions are only needed when
     // dart:mirrors is enabled.
     // TODO(jmesserly): do we even need this for mirrors, since statics are not
@@ -2503,8 +2509,7 @@
   }
 
   /// Emits a Dart [type] into code.
-  js_ast.Expression _emitType(DartType type) =>
-      type.accept(this) as js_ast.Expression;
+  js_ast.Expression _emitType(DartType type) => type.accept(this);
 
   js_ast.Expression _emitInvalidNode(Node node, [String message = '']) {
     if (message.isNotEmpty) message += ' ';
@@ -2748,7 +2753,7 @@
       _emitTypeParameter(type.parameter);
 
   js_ast.Identifier _emitTypeParameter(TypeParameter t) =>
-      js_ast.Identifier(getTypeParameterName(t));
+      _emitIdentifier(getTypeParameterName(t));
 
   @override
   js_ast.Expression visitTypedefType(TypedefType type) =>
@@ -2799,7 +2804,7 @@
 
   List<js_ast.Identifier> _emitTypeFormals(List<TypeParameter> typeFormals) {
     return typeFormals
-        .map((t) => js_ast.Identifier(getTypeParameterName(t)))
+        .map((t) => _emitIdentifier(getTypeParameterName(t)))
         .toList();
   }
 
@@ -2813,7 +2818,7 @@
     emitGeneratorFn(List<js_ast.Parameter> getParameters(js_ast.Block jsBody)) {
       var savedController = _asyncStarController;
       _asyncStarController = function.asyncMarker == AsyncMarker.AsyncStar
-          ? js_ast.TemporaryId('stream')
+          ? _emitTemporaryId('stream')
           : null;
 
       js_ast.Expression gen;
@@ -2831,7 +2836,7 @@
         gen = genFn;
         if (name != null) {
           gen = js_ast.NamedFunction(
-              js_ast.TemporaryId(
+              _emitTemporaryId(
                   js_ast.friendlyNameForDartOperator[name] ?? name),
               genFn);
         }
@@ -3004,11 +3009,11 @@
     }
 
     for (var p in f.positionalParameters.take(f.requiredParameterCount)) {
-      var jsParam = js_ast.Identifier(p.name);
+      var jsParam = _emitIdentifier(p.name);
       initParameter(p, jsParam);
     }
     for (var p in f.positionalParameters.skip(f.requiredParameterCount)) {
-      var jsParam = js_ast.Identifier(p.name);
+      var jsParam = _emitIdentifier(p.name);
       var defaultValue = _defaultParamValue(p);
       if (defaultValue != null) {
         body.add(js.statement(
@@ -3085,7 +3090,7 @@
 
   js_ast.Statement _visitStatement(Statement s) {
     if (s == null) return null;
-    var result = s.accept(this) as js_ast.Statement;
+    var result = s.accept(this);
     // TODO(jmesserly): is the `is! Block` still necessary?
     if (s is! Block) result.sourceInformation = _nodeStart(s);
 
@@ -3156,7 +3161,7 @@
     if (e is ConstantExpression) {
       return visitConstant(e.constant);
     }
-    var result = e.accept(this) as js_ast.Expression;
+    var result = e.accept(this);
     result.sourceInformation ??= _nodeStart(e);
     return result;
   }
@@ -3483,7 +3488,7 @@
       }
 
       if (variableIsReferenced(node.variable.name, iterable)) {
-        var temp = js_ast.TemporaryId('iter');
+        var temp = _emitTemporaryId('iter');
         return js_ast.Block([
           iterable.toVariableDeclaration(temp),
           js_ast.ForOf(init, temp, body)
@@ -3519,7 +3524,7 @@
                 .firstWhere((p) => p.isFactory && p.name.name == '')),
         [_visitExpression(node.iterable)]);
 
-    var iter = js_ast.TemporaryId('iter');
+    var iter = _emitTemporaryId('iter');
     return js.statement(
         '{'
         '  let # = #;'
@@ -3552,7 +3557,7 @@
     var cases = <js_ast.SwitchCase>[];
 
     if (_inLabeledContinueSwitch) {
-      var labelState = js_ast.TemporaryId("labelState");
+      var labelState = _emitTemporaryId("labelState");
       // TODO(markzipan): Retrieve the real label name with source offsets
       var labelName = 'SL${_switchLabelStates.length}';
       _switchLabelStates[node] = _SwitchLabelState(labelName, labelState);
@@ -3859,9 +3864,9 @@
     var name = v.name;
     if (name == null || name.startsWith('#')) {
       name = name == null ? 't${_tempVariables.length}' : name.substring(1);
-      return _tempVariables.putIfAbsent(v, () => js_ast.TemporaryId(name));
+      return _tempVariables.putIfAbsent(v, () => _emitTemporaryId(name));
     }
-    return js_ast.Identifier(name);
+    return _emitIdentifier(name);
   }
 
   /// Emits the declaration of a variable.
@@ -4516,21 +4521,21 @@
                 : 'function() { return super[#]; }',
             [jsName]);
 
-        return js_ast.Method(js_ast.TemporaryId(name), fn,
+        return js_ast.Method(_emitTemporaryId(name), fn,
             isGetter: !setter, isSetter: setter);
       } else {
         var function = member.function;
         var params = [
           ..._emitTypeFormals(function.typeParameters),
           for (var param in function.positionalParameters)
-            js_ast.Identifier(param.name),
+            _emitIdentifier(param.name),
           if (function.namedParameters.isNotEmpty) namedArgumentTemp,
         ];
 
         var fn = js.fun(
             'function(#) { return super[#](#); }', [params, jsName, params]);
         name = js_ast.friendlyNameForDartOperator[name] ?? name;
-        return js_ast.Method(js_ast.TemporaryId(name), fn);
+        return js_ast.Method(_emitTemporaryId(name), fn);
       }
     });
     return js_ast.PropertyAccess(js_ast.This(), jsMethod.name);
@@ -4766,7 +4771,9 @@
   @override
   js_ast.Expression visitConstructorInvocation(ConstructorInvocation node) {
     var ctor = node.target;
+    var ctorClass = ctor.enclosingClass;
     var args = node.arguments;
+    if (isJSAnonymousType(ctorClass)) return _emitObjectLiteral(args);
     var result = js_ast.New(_emitConstructorName(node.constructedType, ctor),
         _emitArgumentList(args, types: false));
 
@@ -4919,73 +4926,19 @@
   @override
   js_ast.Expression visitListConcatenation(ListConcatenation node) {
     // Only occurs inside unevaluated constants.
-    List<js_ast.Expression> entries = [];
-    _concatenate(Expression node) {
-      if (node is ListConcatenation) {
-        node.lists.forEach(_concatenate);
-      } else {
-        node.accept(this);
-        if (node is ConstantExpression) {
-          var list = node.constant as ListConstant;
-          entries.addAll(list.entries.map(visitConstant));
-        } else if (node is ListLiteral) {
-          entries.addAll(node.expressions.map(_visitExpression));
-        }
-      }
-    }
-
-    node.lists.forEach(_concatenate);
-    return _emitConstList(node.typeArgument, entries);
+    throw UnsupportedError("List concatenation");
   }
 
   @override
   js_ast.Expression visitSetConcatenation(SetConcatenation node) {
     // Only occurs inside unevaluated constants.
-    List<js_ast.Expression> entries = [];
-    _concatenate(Expression node) {
-      if (node is SetConcatenation) {
-        node.sets.forEach(_concatenate);
-      } else {
-        node.accept(this);
-        if (node is ConstantExpression) {
-          var set = node.constant as SetConstant;
-          entries.addAll(set.entries.map(visitConstant));
-        } else if (node is SetLiteral) {
-          entries.addAll(node.expressions.map(_visitExpression));
-        }
-      }
-    }
-
-    node.sets.forEach(_concatenate);
-    return _emitConstSet(node.typeArgument, entries);
+    throw UnsupportedError("Set concatenation");
   }
 
   @override
   js_ast.Expression visitMapConcatenation(MapConcatenation node) {
     // Only occurs inside unevaluated constants.
-    List<js_ast.Expression> entries = [];
-    _concatenate(Expression node) {
-      if (node is MapConcatenation) {
-        node.maps.forEach(_concatenate);
-      } else {
-        node.accept(this);
-        if (node is ConstantExpression) {
-          var map = node.constant as MapConstant;
-          for (var entry in map.entries) {
-            entries.add(visitConstant(entry.key));
-            entries.add(visitConstant(entry.value));
-          }
-        } else if (node is MapLiteral) {
-          for (var entry in node.entries) {
-            entries.add(_visitExpression(entry.key));
-            entries.add(_visitExpression(entry.value));
-          }
-        }
-      }
-    }
-
-    node.maps.forEach(_concatenate);
-    return _emitConstMap(node.keyType, node.valueType, entries);
+    throw UnsupportedError("Map concatenation");
   }
 
   @override
@@ -4995,6 +4948,12 @@
   }
 
   @override
+  js_ast.Expression visitFileUriExpression(FileUriExpression node) {
+    // Only occurs inside unevaluated constants.
+    throw UnsupportedError("File URI expression");
+  }
+
+  @override
   js_ast.Expression visitIsExpression(IsExpression node) {
     return _emitIsExpression(node.operand, node.type);
   }
@@ -5355,7 +5314,7 @@
     }
     var constAliasString = "C${constAliasCache.length}";
     var constAliasProperty = propertyName(constAliasString);
-    var constAliasId = js_ast.TemporaryId(constAliasString);
+    var constAliasId = _emitTemporaryId(constAliasString);
     var constAccessor =
         js.call("# || #.#", [constAliasId, _constTable, constAliasProperty]);
     constAliasCache[node] = constAccessor;
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 9044034..2059f37 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -2,43 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
-    show ConstantEvaluator, SimpleErrorReporter;
-
-import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
 import 'package:kernel/target/targets.dart';
-import 'package:kernel/type_environment.dart';
-import 'kernel_helpers.dart';
 
 /// Implements constant evaluation for dev compiler:
 ///
 /// [isConstant] determines if an expression is constant.
 /// [evaluate] computes the value of a constant expression, if available.
 class DevCompilerConstants {
-  final _ConstantVisitor _visitor;
-  final ConstantEvaluator _evaluator;
-
-  DevCompilerConstants(
-      TypeEnvironment types, Map<String, String> declaredVariables)
-      : _visitor = _ConstantVisitor(types.coreTypes),
-        _evaluator = ConstantEvaluator(const DevCompilerConstantsBackend(),
-            declaredVariables, types, const _ErrorReporter());
+  DevCompilerConstants();
 
   /// Determines if an expression is constant.
-  bool isConstant(Expression e) => _visitor.isConstant(e);
+  bool isConstant(Expression e) => e is ConstantExpression;
 
   /// Evaluates [e] to find its constant value, returning `null` if evaluation
   /// failed, or if the constant was unavailable.
   ///
   /// Returns [NullConstant] to represent the `null` value.
   Constant evaluate(Expression e) {
-    if (e == null) return null;
-
-    Constant result = _evaluator.evaluate(e);
-    return result is UnevaluatedConstant ? null : result;
+    return e is ConstantExpression ? e.constant : null;
   }
 
   /// If [node] is an annotation with a field named [name], returns that field's
@@ -60,7 +42,6 @@
   ///
   /// Given the node for `@MyAnnotation('FooBar')` this will return `'FooBar'`.
   Object getFieldValueFromAnnotation(Expression node, String name) {
-    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       if (constant is InstanceConstant) {
@@ -97,7 +78,6 @@
   }
 
   Object _evaluateAnnotationArgument(Expression node) {
-    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       if (constant is PrimitiveConstant) return constant.value;
@@ -112,88 +92,6 @@
   }
 }
 
-/// Finds constant expressions as defined in Dart language spec 4th ed,
-/// 16.1 Constants.
-class _ConstantVisitor extends ExpressionVisitor<bool> {
-  final CoreTypes coreTypes;
-  _ConstantVisitor(this.coreTypes);
-
-  bool isConstant(Expression e) => e.accept(this) as bool;
-
-  @override
-  defaultExpression(node) => false;
-  @override
-  defaultBasicLiteral(node) => true;
-  @override
-  visitTypeLiteral(node) => true; // TODO(jmesserly): deferred libraries?
-  @override
-  visitSymbolLiteral(node) => true;
-  @override
-  visitListLiteral(node) => node.isConst;
-  @override
-  visitMapLiteral(node) => node.isConst;
-  @override
-  visitStaticInvocation(node) {
-    return node.isConst ||
-        node.target == coreTypes.identicalProcedure &&
-            node.arguments.positional.every(isConstant) ||
-        isFromEnvironmentInvocation(coreTypes, node) &&
-            node.arguments.positional.every(isConstant) &&
-            node.arguments.named.every((n) => isConstant(n.value));
-  }
-
-  @override
-  visitDirectMethodInvocation(node) {
-    return node.receiver is BasicLiteral &&
-        isOperatorMethodName(node.name.name) &&
-        node.arguments.positional.every((p) => p is BasicLiteral);
-  }
-
-  @override
-  visitMethodInvocation(node) {
-    return node.receiver is BasicLiteral &&
-        isOperatorMethodName(node.name.name) &&
-        node.arguments.positional.every((p) => p is BasicLiteral);
-  }
-
-  @override
-  visitConstructorInvocation(node) => node.isConst;
-  @override
-  visitStringConcatenation(node) =>
-      node.expressions.every((e) => e is BasicLiteral);
-  @override
-  visitStaticGet(node) {
-    var target = node.target;
-    return target is Procedure || target is Field && target.isConst;
-  }
-
-  @override
-  visitVariableGet(node) => node.variable.isConst;
-  @override
-  visitNot(node) {
-    var operand = node.operand;
-    return operand is BoolLiteral ||
-        operand is DirectMethodInvocation &&
-            visitDirectMethodInvocation(operand) ||
-        operand is MethodInvocation && visitMethodInvocation(operand);
-  }
-
-  @override
-  visitLogicalExpression(node) =>
-      node.left is BoolLiteral && node.right is BoolLiteral;
-  @override
-  visitConditionalExpression(node) =>
-      node.condition is BoolLiteral &&
-      node.then is BoolLiteral &&
-      node.otherwise is BoolLiteral;
-
-  @override
-  visitLet(Let node) {
-    var init = node.variable.initializer;
-    return (init == null || isConstant(init)) && isConstant(node.body);
-  }
-}
-
 /// Implement the class for compiler specific behavior.
 class DevCompilerConstantsBackend extends ConstantsBackend {
   const DevCompilerConstantsBackend();
@@ -218,11 +116,3 @@
     }
   }
 }
-
-class _ErrorReporter extends SimpleErrorReporter {
-  const _ErrorReporter();
-
-  // Ignore reported errors.
-  @override
-  reportMessage(Uri uri, int offset, String message) {}
-}
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 3b3b66a..45efb1c 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -17,11 +17,16 @@
   return null;
 }
 
-final Pattern _syntheticTypeCharacters = RegExp('[&^#.]');
+final Pattern _syntheticTypeCharacters = RegExp('[&^#.|]');
 
-String _escapeIdentifier(String identifier) {
+String escapeIdentifier(String identifier) {
   // Remove the special characters used to encode mixin application class names
-  // which are legal in Kernel, but not in JavaScript.
+  // and extension method / parameter names which are legal in Kernel, but not
+  // in JavaScript.
+  //
+  // Note, there is an implicit assumption here that we won't have
+  // collisions since everything is mapped to \$.  That may work out fine given
+  // how these are sythesized, but may need to revisit.
   return identifier?.replaceAll(_syntheticTypeCharacters, r'$');
 }
 
@@ -32,13 +37,13 @@
 ///
 /// In the current encoding, generic classes are generated in a function scope
 /// which avoids name clashes of the escaped class name.
-String getLocalClassName(Class node) => _escapeIdentifier(node.name);
+String getLocalClassName(Class node) => escapeIdentifier(node.name);
 
 /// Returns the escaped name for the type parameter [node].
 ///
 /// In the current encoding, generic classes are generated in a function scope
 /// which avoids name clashes of the escaped parameter name.
-String getTypeParameterName(TypeParameter node) => _escapeIdentifier(node.name);
+String getTypeParameterName(TypeParameter node) => escapeIdentifier(node.name);
 
 String getTopLevelName(NamedNode n) {
   if (n is Procedure) return n.name.name;
@@ -101,7 +106,6 @@
 /// This function works regardless of whether the CFE is evaluating constants,
 /// or whether the constant is a field reference (such as "anonymous" above).
 Class getAnnotationClass(Expression node) {
-  node = unwrapUnevaluatedConstant(node);
   if (node is ConstantExpression) {
     var constant = node.constant;
     if (constant is InstanceConstant) return constant.classNode;
@@ -114,19 +118,6 @@
   return null;
 }
 
-Expression unwrapUnevaluatedConstant(Expression node) {
-  // TODO(jmesserly): see if we can configure CFE to preseve the original
-  // expression, rather than wrapping in an UnevaluatedConstant and then
-  // a ConstantExpression.
-  if (node is ConstantExpression) {
-    var constant = node.constant;
-    if (constant is UnevaluatedConstant) {
-      return constant.expression;
-    }
-  }
-  return node;
-}
-
 /// Returns true if [name] is an operator method that is available on primitive
 /// types (`int`, `double`, `num`, `String`, `bool`).
 ///
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index 33242c9..07810f3 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -53,8 +53,7 @@
   void exitFunction(FunctionNode fn) => _variableInference.exitFunction(fn);
 
   /// Returns true if [expr] can be null.
-  bool isNullable(Expression expr) =>
-      expr != null ? expr.accept(this) as bool : false;
+  bool isNullable(Expression expr) => expr != null ? expr.accept(this) : false;
 
   @override
   defaultExpression(Expression node) => true;
@@ -230,7 +229,7 @@
   @override
   visitConstantExpression(ConstantExpression node) {
     var c = node.constant;
-    if (c is UnevaluatedConstant) return c.expression.accept(this) as bool;
+    if (c is UnevaluatedConstant) return c.expression.accept(this);
     if (c is PrimitiveConstant) return c.value == null;
     return false;
   }
@@ -249,7 +248,6 @@
 
   bool _isInternalAnnotationField(
       Expression node, String fieldName, String className) {
-    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       return constant is InstanceConstant &&
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
index d8b4fa6..fbb7af4 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
@@ -89,4 +89,4 @@
 }
 
 void main(List<String> arguments) =>
-    runMe(arguments, createContext, "testing.json");
+    runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
index 2aced38..cec6887 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
@@ -105,4 +105,4 @@
 }
 
 void main(List<String> arguments) =>
-    runMe(arguments, createContext, "testing.json");
+    runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart b/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
index 0ed9dfb..b2ddfde 100644
--- a/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
@@ -22,4 +22,4 @@
 }
 
 void main(List<String> arguments) =>
-    runMe(arguments, createContext, "testing.json");
+    runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
index 515007e..8a23a66 100644
--- a/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
@@ -29,4 +29,4 @@
 }
 
 void main(List<String> arguments) =>
-    runMe(arguments, createContext, "testing.json");
+    runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index 17d5704..ff8e482 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -52,7 +52,11 @@
         defaultsTo: '9222')
     ..addMultiOption('enable-experiment',
         help: 'Run with specified experiments enabled.')
-    ..addOption('binary', abbr: 'b', help: 'Runtime binary path.');
+    ..addOption('binary', abbr: 'b', help: 'Runtime binary path.')
+    ..addOption('mode',
+        help: 'Option to (compile|run|all).  Default is all (compile and run).',
+        allowed: ['compile', 'run', 'all'],
+        defaultsTo: 'all');
 
   var options = parser.parse(args);
   if (options['help']) {
@@ -73,6 +77,9 @@
   var experiments = options['enable-experiment'] as List;
   var summaries = options['summary'] as List;
   var port = int.parse(options['port'] as String);
+  var mode = options['mode'] as String;
+  var compile = mode == 'compile' || mode == 'all';
+  var run = mode == 'run' || mode == 'all';
 
   var entry = p.canonicalize(options.rest.first);
   var libRoot = p.dirname(entry);
@@ -157,41 +164,44 @@
       dartSdk, 'lib', '_internal', kernel ? 'ddc_sdk.dill' : 'ddc_sdk.sum');
 
   ProcessResult result;
-  var ddcArgs = [
-    if (kernel) '--kernel',
-    if (kernel && summarizeText)
-      '--summarize-text',
-    '--modules=$mod',
-    '--dart-sdk-summary=$ddcSdk',
-    // TODO(nshahan) Cleanup when we settle on using or removing library-root.
-    if (!kernel)
-      '--library-root=$libRoot',
-    for (var summary in summaries) '--summary=$summary',
-    for (var experiment in experiments) '--enable-experiment=$experiment',
-    '-o',
-    p.setExtension(entry, '.js'),
-    entry
-  ];
+  if (compile) {
+    var ddcArgs = [
+      if (kernel) '--kernel',
+      if (kernel && summarizeText)
+        '--summarize-text',
+      '--modules=$mod',
+      '--dart-sdk-summary=$ddcSdk',
+      // TODO(nshahan) Cleanup when we settle on using or removing library-root.
+      if (!kernel)
+        '--library-root=$libRoot',
+      for (var summary in summaries) '--summary=$summary',
+      for (var experiment in experiments) '--enable-experiment=$experiment',
+      '-o',
+      p.setExtension(entry, '.js'),
+      entry
+    ];
 
-  result = runDdc('dartdevc', ddcArgs);
-  await echoResult(result);
+    result = runDdc('dartdevc', ddcArgs);
+    await echoResult(result);
+  }
 
-  if (chrome) {
-    String chromeBinary;
-    if (binary != null) {
-      chromeBinary = binary;
-    } else if (Platform.isWindows) {
-      chromeBinary =
-          'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
-    } else if (Platform.isMacOS) {
-      chromeBinary =
-          '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
-    } else {
-      // Assume Linux
-      chromeBinary = 'google-chrome';
-    }
+  if (run) {
+    if (chrome) {
+      String chromeBinary;
+      if (binary != null) {
+        chromeBinary = binary;
+      } else if (Platform.isWindows) {
+        chromeBinary =
+            'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
+      } else if (Platform.isMacOS) {
+        chromeBinary =
+            '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+      } else {
+        // Assume Linux
+        chromeBinary = 'google-chrome';
+      }
 
-    var html = """
+      var html = '''
 <script src='$requirePath/require.js'></script>
 <script>
   require.config({
@@ -207,72 +217,73 @@
     app.$libname.main();
   });
 </script>
-""";
-    var htmlFile = p.setExtension(entry, '.html');
-    new File(htmlFile).writeAsStringSync(html);
-    var tmp = p.join(Directory.systemTemp.path, 'ddc');
+''';
+      var htmlFile = p.setExtension(entry, '.html');
+      new File(htmlFile).writeAsStringSync(html);
+      var tmp = p.join(Directory.systemTemp.path, 'ddc');
 
-    result = Process.runSync(chromeBinary, [
-      '--auto-open-devtools-for-tabs',
-      '--allow-file-access-from-files',
-      '--remote-debugging-port=$port',
-      '--user-data-dir=$tmp',
-      htmlFile
-    ]);
-  } else if (node) {
-    var nodePath = '$sdkJsPath:$libRoot';
-    var runjs = '''
-    let source_maps;
-    try {
-      source_maps = require('source-map-support');
-      source_maps.install();
-    } catch(e) {
-    }
-    let sdk = require(\"dart_sdk\");
-    let main = require(\"./$basename\").$libname.main;
-    try {
-      sdk._isolate_helper.startRootIsolate(main, []);
-    } catch(e) {
-      if (!source_maps) {
-        console.log('For Dart source maps: npm install source-map-support');
-      }
-      sdk.core.print(sdk.dart.stackTrace(e));
-      process.exit(1);
-    }
-    ''';
-    var nodeFile = p.setExtension(entry, '.run.js');
-    new File(nodeFile).writeAsStringSync(runjs);
-    var nodeBinary = binary ?? 'node';
-    result = Process.runSync(
-        nodeBinary, ['--inspect=localhost:$port', nodeFile],
-        environment: {'NODE_PATH': nodePath});
-  } else if (d8) {
-    // Fix SDK import.  `d8` doesn't let us set paths, so we need a full path
-    // to the SDK.
-
-    var jsFile = File(p.setExtension(entry, '.js'));
-    var jsContents = jsFile.readAsStringSync();
-    jsContents = jsContents.replaceFirst(
-        "from 'dart_sdk.js'", "from '$sdkJsPath/dart_sdk.js'");
-    jsFile.writeAsStringSync(jsContents);
-
-    var runjs = '''
-    import { dart, _isolate_helper } from '$sdkJsPath/dart_sdk.js';
-    import { $libname } from '$basename.js';
-    let main = $libname.main;
-    try {
-      _isolate_helper.startRootIsolate(() => {}, []);
-      main();
-    } catch(e) {
-      console.error(e);
-    }
-    ''';
-    var d8File = p.setExtension(entry, '.d8.js');
-    new File(d8File).writeAsStringSync(runjs);
-    var d8Binary = binary ?? p.join(dartCheckoutPath, _d8executable);
-    result = Process.runSync(d8Binary, ['--module', d8File]);
+      result = Process.runSync(chromeBinary, [
+        '--auto-open-devtools-for-tabs',
+        '--allow-file-access-from-files',
+        '--remote-debugging-port=$port',
+        '--user-data-dir=$tmp',
+        htmlFile
+      ]);
+    } else if (node) {
+      var nodePath = '$sdkJsPath:$libRoot';
+      var runjs = '''
+let source_maps;
+try {
+  source_maps = require('source-map-support');
+  source_maps.install();
+} catch(e) {
+}
+let sdk = require(\"dart_sdk\");
+let main = require(\"./$basename\").$libname.main;
+try {
+  sdk._isolate_helper.startRootIsolate(main, []);
+} catch(e) {
+  if (!source_maps) {
+    console.log('For Dart source maps: npm install source-map-support');
   }
-  await echoResult(result);
+  sdk.core.print(sdk.dart.stackTrace(e));
+  process.exit(1);
+}
+''';
+      var nodeFile = p.setExtension(entry, '.run.js');
+      new File(nodeFile).writeAsStringSync(runjs);
+      var nodeBinary = binary ?? 'node';
+      result = Process.runSync(
+          nodeBinary, ['--inspect=localhost:$port', nodeFile],
+          environment: {'NODE_PATH': nodePath});
+    } else if (d8) {
+      // Fix SDK import.  `d8` doesn't let us set paths, so we need a full path
+      // to the SDK.
+
+      var jsFile = File(p.setExtension(entry, '.js'));
+      var jsContents = jsFile.readAsStringSync();
+      jsContents = jsContents.replaceFirst(
+          "from 'dart_sdk.js'", "from '$sdkJsPath/dart_sdk.js'");
+      jsFile.writeAsStringSync(jsContents);
+
+      var runjs = '''
+import { dart, _isolate_helper } from '$sdkJsPath/dart_sdk.js';
+import { $libname } from '$basename.js';
+let main = $libname.main;
+try {
+  _isolate_helper.startRootIsolate(() => {}, []);
+  main();
+} catch(e) {
+  console.error(e);
+}
+''';
+      var d8File = p.setExtension(entry, '.d8.js');
+      new File(d8File).writeAsStringSync(runjs);
+      var d8Binary = binary ?? p.join(dartCheckoutPath, _d8executable);
+      result = Process.runSync(d8Binary, ['--module', d8File]);
+    }
+    await echoResult(result);
+  }
 }
 
 String get _d8executable {
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 11e2a33..004097b 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -75,11 +75,9 @@
   File(librarySpecPath)
       .copySync(p.join(p.dirname(outputDir), p.basename(librarySpecPath)));
 
-  var jsModule = ProgramCompiler(
-      component,
-      compilerResult.classHierarchy,
-      SharedCompilerOptions(moduleName: 'dart_sdk'),
-      {}).emitModule(component, [], [], {});
+  var jsModule = ProgramCompiler(component, compilerResult.classHierarchy,
+          SharedCompilerOptions(moduleName: 'dart_sdk'))
+      .emitModule(component, [], [], {});
   var moduleFormats = {
     'amd': ModuleFormat.amd,
     'common': ModuleFormat.common,
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index df8bffa..954a653 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -85,12 +85,12 @@
    * This finds the first point where two strings differ, and returns
    * a text describing the difference.
    *
-   * For small strings (length less than 20) nothing is done, and null is
+   * For small strings (length less than 20) nothing is done, and "" is
    * returned. Small strings can be compared visually, but for longer strings
    * only a slice containing the first difference will be shown.
    */
   static String _stringDifference(String expected, String actual) {
-    if (expected.length < 20 && actual.length < 20) return null;
+    if (expected.length < 20 && actual.length < 20) return "";
     for (int i = 0; i < expected.length && i < actual.length; i++) {
       if (expected.codeUnitAt(i) != actual.codeUnitAt(i)) {
         int start = i;
@@ -106,18 +106,18 @@
             "Found: <$truncActual>";
       }
     }
-    return null;
+    return "";
   }
 
   /**
    * Checks whether the expected and actual values are equal (using `==`).
    */
-  static void equals(var expected, var actual, [String reason = null]) {
+  static void equals(var expected, var actual, [String reason = ""]) {
     if (expected == actual) return;
     String msg = _getMessage(reason);
     if (expected is String && actual is String) {
       String stringDifference = _stringDifference(expected, actual);
-      if (stringDifference != null) {
+      if (stringDifference.isNotEmpty) {
         _fail("Expect.equals($stringDifference$msg) fails.");
       }
       _fail("Expect.equals(expected: <${_escapeString(expected)}>"
@@ -129,7 +129,7 @@
   /**
    * Checks whether the actual value is a bool and its value is true.
    */
-  static void isTrue(var actual, [String reason = null]) {
+  static void isTrue(var actual, [String reason = ""]) {
     if (_identical(actual, true)) return;
     String msg = _getMessage(reason);
     _fail("Expect.isTrue($actual$msg) fails.");
@@ -138,7 +138,7 @@
   /**
    * Checks whether the actual value is a bool and its value is false.
    */
-  static void isFalse(var actual, [String reason = null]) {
+  static void isFalse(var actual, [String reason = ""]) {
     if (_identical(actual, false)) return;
     String msg = _getMessage(reason);
     _fail("Expect.isFalse($actual$msg) fails.");
@@ -147,7 +147,7 @@
   /**
    * Checks whether [actual] is null.
    */
-  static void isNull(actual, [String reason = null]) {
+  static void isNull(actual, [String reason = ""]) {
     if (null == actual) return;
     String msg = _getMessage(reason);
     _fail("Expect.isNull(actual: <$actual>$msg) fails.");
@@ -156,7 +156,7 @@
   /**
    * Checks whether [actual] is not null.
    */
-  static void isNotNull(actual, [String reason = null]) {
+  static void isNotNull(actual, [String reason = ""]) {
     if (null != actual) return;
     String msg = _getMessage(reason);
     _fail("Expect.isNotNull(actual: <$actual>$msg) fails.");
@@ -166,7 +166,7 @@
    * Checks whether the expected and actual values are identical
    * (using `identical`).
    */
-  static void identical(var expected, var actual, [String reason = null]) {
+  static void identical(var expected, var actual, [String reason = ""]) {
     if (_identical(expected, actual)) return;
     String msg = _getMessage(reason);
     if (expected is String && actual is String) {
@@ -187,17 +187,20 @@
    * That is, `objects[i]` is identical to objects with indices in
    * `_findEquivalences(objects)[i]`.
    *
-   * Uses `null` for objects that are only identical to themselves.
+   * Uses `[]` for objects that are only identical to themselves.
    */
   static List<List<int>> _findEquivalences(List<Object> objects) {
-    var equivalences = new List<List<int>>(objects.length);
+    var equivalences = new List<List<int>>.generate(objects.length, (_) => []);
     for (int i = 0; i < objects.length; i++) {
-      if (equivalences[i] != null) continue;
+      if (equivalences[i].isNotEmpty) continue;
       var o = objects[i];
       for (int j = i + 1; j < objects.length; j++) {
-        if (equivalences[j] != null) continue;
+        if (equivalences[j].isNotEmpty) continue;
         if (_identical(o, objects[j])) {
-          equivalences[j] = (equivalences[i] ??= <int>[i])..add(j);
+          if (equivalences[i].isEmpty) {
+            equivalences[i].add(i);
+          }
+          equivalences[j] = equivalences[i]..add(j);
         }
       }
     }
@@ -211,7 +214,7 @@
       buffer.write(separator);
       separator = ",";
       var equivalence = equivalences[i];
-      if (equivalence == null) {
+      if (equivalence.isEmpty) {
         buffer.write('_');
       } else {
         int first = equivalence[0];
@@ -223,12 +226,12 @@
     }
   }
 
-  static void allIdentical(Iterable<Object> objects, [String reason]) {
+  static void allIdentical(List<Object> objects, [String reason = ""]) {
     if (objects.length <= 1) return;
     String msg = _getMessage(reason);
     var equivalences = _findEquivalences(objects);
     var first = equivalences[0];
-    if (first != null && first.length == objects.length) return;
+    if (first.isNotEmpty && first.length == objects.length) return;
     var buffer = new StringBuffer("Expect.allIdentical([");
     _writeEquivalences(objects, equivalences, buffer);
     buffer..write("]")..write(msg)..write(")");
@@ -239,7 +242,7 @@
    * Checks whether the expected and actual values are *not* identical
    * (using `identical`).
    */
-  static void notIdentical(var unexpected, var actual, [String reason = null]) {
+  static void notIdentical(var unexpected, var actual, [String reason = ""]) {
     if (!_identical(unexpected, actual)) return;
     String msg = _getMessage(reason);
     _fail("Expect.notIdentical(expected and actual: <$actual>$msg) fails.");
@@ -248,13 +251,13 @@
   /**
    * Checks that no two [objects] are `identical`.
    */
-  static void allDistinct(List<Object> objects, [String reason = null]) {
+  static void allDistinct(List<Object> objects, [String reason = ""]) {
     String msg = _getMessage(reason);
     var equivalences = _findEquivalences(objects);
 
     bool hasEquivalence = false;
     for (int i = 0; i < equivalences.length; i++) {
-      if (equivalences[i] != null) {
+      if (equivalences[i].isNotEmpty) {
         hasEquivalence = true;
         break;
       }
@@ -278,8 +281,8 @@
    * value 4 significant digits smaller than the value given for expected.
    */
   static void approxEquals(num expected, num actual,
-      [num tolerance = null, String reason = null]) {
-    if (tolerance == null) {
+      [num tolerance = -1, String reason = ""]) {
+    if (tolerance < 0) {
       tolerance = (expected / 1e4).abs();
     }
     // Note: use !( <= ) rather than > so we fail on NaNs
@@ -290,7 +293,7 @@
         'tolerance:<$tolerance>$msg) fails');
   }
 
-  static void notEquals(unexpected, actual, [String reason = null]) {
+  static void notEquals(unexpected, actual, [String reason = ""]) {
     if (unexpected != actual) return;
     String msg = _getMessage(reason);
     _fail("Expect.notEquals(unexpected: <$unexpected>, actual:<$actual>$msg) "
@@ -303,7 +306,7 @@
    * used by the standard list implementation.  It should also produce nicer
    * error messages than just calling `Expect.equals(expected, actual)`.
    */
-  static void listEquals(List expected, List actual, [String reason = null]) {
+  static void listEquals(List expected, List actual, [String reason = ""]) {
     String msg = _getMessage(reason);
     int n = (expected.length < actual.length) ? expected.length : actual.length;
     for (int i = 0; i < n; i++) {
@@ -327,7 +330,7 @@
    * the semantics of [Map.containsKey] to determine what "same" means. For
    * each key, checks that the values in both maps are equal using `==`.
    */
-  static void mapEquals(Map expected, Map actual, [String reason = null]) {
+  static void mapEquals(Map expected, Map actual, [String reason = ""]) {
     String msg = _getMessage(reason);
 
     // Make sure all of the values are present in both, and they match.
@@ -352,7 +355,7 @@
    * this method shows where the mismatch starts and ends.
    */
   static void stringEquals(String expected, String actual,
-      [String reason = null]) {
+      [String reason = ""]) {
     if (expected == actual) return;
 
     String msg = _getMessage(reason);
@@ -435,7 +438,7 @@
    * every element of [actual] is also in [expected].
    */
   static void setEquals(Iterable expected, Iterable actual,
-      [String reason = null]) {
+      [String reason = ""]) {
     final missingSet = new Set.from(expected);
     missingSet.removeAll(actual);
     final extraSet = new Set.from(actual);
@@ -517,6 +520,8 @@
     }
   }
 
+  static bool _defaultCheck([dynamic e]) => true;
+
   /**
    * Calls the function [f] and verifies that it throws a `T`.
    * The optional [check] function can provide additional validation
@@ -533,8 +538,13 @@
    * exception is not caught by [Expect.throws]. The test is still considered
    * failing.
    */
-  static void throws<T>(void f(), [bool check(T error), String reason]) {
-    String msg = reason == null ? "" : "($reason)";
+  static void throws<T>(void f(),
+      [bool check(T error) = _defaultCheck, String reason = ""]) {
+    // TODO(vsm): Make check nullable.  Existing tests pass null to set
+    // a reason.
+    check = check ?? _defaultCheck;
+    reason = reason ?? "";
+    String msg = reason.isEmpty ? "" : "($reason)";
     if (f is! Function()) {
       // Only throws from executing the function body should count as throwing.
       // The failure to even call `f` should throw outside the try/catch.
@@ -545,7 +555,7 @@
     } on Object catch (e, s) {
       // A test failure doesn't count as throwing.
       if (e is ExpectException) rethrow;
-      if (e is T && (check == null || check(e))) return;
+      if (e is T && check(e as dynamic)) return;
       // Throws something unexpected.
       String type = "";
       if (T != dynamic && T != Object) {
@@ -557,45 +567,44 @@
     _fail('Expect.throws$msg fails: Did not throw');
   }
 
-  static void throwsArgumentError(void f(), [String reason]) {
-    Expect.throws(
-        f, (error) => error is ArgumentError, reason ?? "ArgumentError");
+  static void throwsArgumentError(void f(), [String reason = "ArgumentError"]) {
+    Expect.throws(f, (error) => error is ArgumentError, reason);
   }
 
-  static void throwsAssertionError(void f(), [String reason]) {
-    Expect.throws(
-        f, (error) => error is AssertionError, reason ?? "AssertionError");
+  static void throwsAssertionError(void f(),
+      [String reason = "AssertionError"]) {
+    Expect.throws(f, (error) => error is AssertionError, reason);
   }
 
-  static void throwsCastError(void f(), [String reason]) {
-    Expect.throws(f, (error) => error is CastError, reason ?? "CastError");
+  static void throwsCastError(void f(), [String reason = "CastError"]) {
+    Expect.throws(f, (error) => error is CastError, reason);
   }
 
-  static void throwsFormatException(void f(), [String reason]) {
-    Expect.throws(
-        f, (error) => error is FormatException, reason ?? "FormatException");
+  static void throwsFormatException(void f(),
+      [String reason = "FormatException"]) {
+    Expect.throws(f, (error) => error is FormatException, reason);
   }
 
-  static void throwsNoSuchMethodError(void f(), [String reason]) {
-    Expect.throws(f, (error) => error is NoSuchMethodError,
-        reason ?? "NoSuchMethodError");
+  static void throwsNoSuchMethodError(void f(),
+      [String reason = "NoSuchMethodError"]) {
+    Expect.throws(f, (error) => error is NoSuchMethodError, reason);
   }
 
-  static void throwsRangeError(void f(), [String reason]) {
-    Expect.throws(f, (error) => error is RangeError, reason ?? "RangeError");
+  static void throwsRangeError(void f(), [String reason = "RangeError"]) {
+    Expect.throws(f, (error) => error is RangeError, reason);
   }
 
-  static void throwsStateError(void f(), [String reason]) {
-    Expect.throws(f, (error) => error is StateError, reason ?? "StateError");
+  static void throwsStateError(void f(), [String reason = "StateError"]) {
+    Expect.throws(f, (error) => error is StateError, reason);
   }
 
-  static void throwsTypeError(void f(), [String reason]) {
-    Expect.throws(f, (error) => error is TypeError, reason ?? "TypeError");
+  static void throwsTypeError(void f(), [String reason = "TypeError"]) {
+    Expect.throws(f, (error) => error is TypeError, reason);
   }
 
-  static void throwsUnsupportedError(void f(), [String reason]) {
-    Expect.throws(
-        f, (error) => error is UnsupportedError, reason ?? "UnsupportedError");
+  static void throwsUnsupportedError(void f(),
+      [String reason = "UnsupportedError"]) {
+    Expect.throws(f, (error) => error is UnsupportedError, reason);
   }
 
   /// Reports that there is an error in the test itself and not the code under
@@ -608,7 +617,7 @@
   }
 
   /// Checks that [object] has type [T].
-  static void type<T>(Object object, [String reason]) {
+  static void type<T>(dynamic object, [String reason = ""]) {
     if (object is T) return;
     String msg = _getMessage(reason);
     _fail("Expect.type($object is $T$msg) fails "
@@ -616,7 +625,7 @@
   }
 
   /// Checks that [object] does not have type [T].
-  static void notType<T>(Object object, [String reason]) {
+  static void notType<T>(dynamic object, [String reason = ""]) {
     if (object is! T) return;
     String msg = _getMessage(reason);
     _fail("Expect.type($object is! $T$msg) fails"
@@ -648,7 +657,7 @@
   }
 
   static String _getMessage(String reason) =>
-      (reason == null) ? "" : ", '$reason'";
+      (reason.isEmpty) ? "" : ", '$reason'";
 
   @alwaysThrows
   static void _fail(String message) {
diff --git a/pkg/expect/lib/matchers_lite.dart b/pkg/expect/lib/matchers_lite.dart
index 004e37e..5b8d11e 100644
--- a/pkg/expect/lib/matchers_lite.dart
+++ b/pkg/expect/lib/matchers_lite.dart
@@ -18,7 +18,7 @@
 
 typedef Matcher = void Function(Object actual);
 
-void expect(Object actual, Object expected) {
+void expect(dynamic actual, dynamic expected) {
   if (expected is Matcher) {
     expected(actual);
   } else {
@@ -27,7 +27,8 @@
 }
 
 Matcher unorderedEquals(Iterable<Object> expected) {
-  return (Object actual) => Expect.setEquals(expected, actual);
+  return (Object actual) =>
+      Expect.setEquals(expected, actual as Iterable<Object>);
 }
 
 fail(String message) {
@@ -40,7 +41,7 @@
 
 Matcher equals(Object expected) {
   if (expected is String) {
-    return (Object actual) => Expect.stringEquals(expected, actual);
+    return (Object actual) => Expect.stringEquals(expected, actual as String);
   } else if (expected is Iterable<Object>) {
     return (dynamic actual) =>
         Expect.listEquals(expected.toList(), actual.toList());
diff --git a/pkg/expect/lib/minitest.dart b/pkg/expect/lib/minitest.dart
index 8082bd5..350b6aa 100644
--- a/pkg/expect/lib/minitest.dart
+++ b/pkg/expect/lib/minitest.dart
@@ -90,11 +90,9 @@
 void test(String description, body()) {
   // TODO(rnystrom): Do something useful with the description.
   for (var group in _groups) {
-    if (group.setUpFunction != null) {
-      var result = group.setUpFunction();
-      if (result is Future) {
-        Expect.testError("setUp() does not support asynchronous functions.");
-      }
+    var result = group.setUpFunction();
+    if (result is Future) {
+      Expect.testError("setUp() does not support asynchronous functions.");
     }
   }
 
@@ -106,12 +104,9 @@
   } finally {
     for (var i = _groups.length - 1; i >= 0; i--) {
       var group = _groups[i];
-      if (group.tearDownFunction != null) {
-        var result = group.tearDownFunction();
-        if (result is Future) {
-          Expect
-              .testError("tearDown() does not support asynchronous functions.");
-        }
+      var result = group.tearDownFunction();
+      if (result is Future) {
+        Expect.testError("tearDown() does not support asynchronous functions.");
       }
     }
   }
@@ -119,17 +114,17 @@
 
 void setUp(body()) {
   // Can't define multiple setUps at the same level.
-  assert(_groups.last.setUpFunction == null);
+  assert(_groups.last.setUpFunction == _defaultAction);
   _groups.last.setUpFunction = body;
 }
 
 void tearDown(body()) {
   // Can't define multiple tearDowns at the same level.
-  assert(_groups.last.tearDownFunction == null);
+  assert(_groups.last.tearDownFunction == _defaultAction);
   _groups.last.tearDownFunction = body;
 }
 
-void expect(Object actual, Object expected, {String reason}) {
+void expect(Object actual, Object expected, {String reason = ""}) {
   // TODO(rnystrom): Do something useful with reason.
   if (expected is! _Expectation) {
     expected = equals(expected);
@@ -152,10 +147,10 @@
     });
 
 Object unorderedEquals(Object value) => new _Expectation((actual) {
-      Expect.setEquals(value, actual);
+      Expect.setEquals(value as Iterable, actual as Iterable);
     });
 
-Object predicate(bool fn(Object value), [String description]) =>
+Object predicate(bool fn(Object value), [String description = ""]) =>
     new _Expectation((actual) {
       Expect.isTrue(fn(actual), description);
     });
@@ -179,7 +174,7 @@
     });
 
 Object closeTo(num value, num tolerance) => new _Expectation((actual) {
-      Expect.approxEquals(value, actual, tolerance);
+      Expect.approxEquals(value, actual as num, tolerance);
     });
 
 /// Succeeds if the actual value is any of the given strings. Unlike matcher's
@@ -192,13 +187,15 @@
       fail("Expected $actual to be one of $expected.");
     });
 
+_defaultAction() {}
+
 /// One level of group() nesting to track an optional [setUp()] and [tearDown()]
 /// function for the group.
 ///
 /// There is also an implicit top level group.
 class _Group {
-  _Action setUpFunction;
-  _Action tearDownFunction;
+  _Action setUpFunction = _defaultAction;
+  _Action tearDownFunction = _defaultAction;
 }
 
 /// A wrapper around an expectation function.
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index bd628d8..c2c76e5 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -4,6 +4,8 @@
 
 library front_end.compiler_options;
 
+import 'package:kernel/ast.dart' as kernel show Library;
+
 import 'package:kernel/target/targets.dart' show Target;
 
 import 'diagnostic_message.dart' show DiagnosticMessageHandler;
@@ -215,6 +217,13 @@
 
   /// Whether to write a file (e.g. a dill file) when reporting a crash.
   bool writeFileOnCrashReport = true;
+
+  /// The current sdk version string, e.g. "2.6.0-edge.sha1hash".
+  /// For instance used for language versioning (specifying the maximum
+  /// version).
+  String currentSdkVersion = "${kernel.Library.defaultLanguageVersionMajor}"
+      "."
+      "${kernel.Library.defaultLanguageVersionMinor}";
 }
 
 /// Parse experimental flag arguments of the form 'flag' or 'no-flag' into a map
diff --git a/pkg/front_end/lib/src/api_unstable/bazel_worker.dart b/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
index 1473017..68939cd 100644
--- a/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
+++ b/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
@@ -48,7 +48,7 @@
 
 export 'compiler_state.dart' show InitializedCompilerState;
 
-import 'util.dart' show equalMaps;
+import 'util.dart' show equalMaps, equalSets;
 
 /// Initializes the compiler for a modular build.
 ///
@@ -56,6 +56,7 @@
 /// as necessary based on [workerInputDigests].
 Future<InitializedCompilerState> initializeIncrementalCompiler(
     InitializedCompilerState oldState,
+    Set<String> tags,
     Uri sdkSummary,
     Uri packagesFile,
     Uri librariesSpecificationUri,
@@ -84,7 +85,8 @@
   if (oldState == null ||
       oldState.incrementalCompiler == null ||
       oldState.incrementalCompiler.outlineOnly != outlineOnly ||
-      !equalMaps(oldState.options.experimentalFlags, experimentalFlags)) {
+      !equalMaps(oldState.options.experimentalFlags, experimentalFlags) ||
+      !equalSets(oldState.tags, tags)) {
     // No - or immediately not correct - previous state.
     startOver = true;
 
@@ -115,7 +117,7 @@
       ..experimentalFlags = experimentalFlags;
 
     processedOpts = new ProcessedOptions(options: options);
-    cachedSdkInput = WorkerInputComponent(
+    cachedSdkInput = new WorkerInputComponent(
         sdkDigest, await processedOpts.loadSdkSummary(null));
     workerInputCache[sdkSummary] = cachedSdkInput;
 
@@ -193,7 +195,7 @@
     if (summaryDigest == null) {
       throw new StateError("Expected to get digest for $summary");
     }
-    WorkerInputComponent cachedInput = WorkerInputComponent(
+    WorkerInputComponent cachedInput = new WorkerInputComponent(
         summaryDigest,
         await processedOpts.loadComponent(
             await fileSystem.entityForUri(summary).readAsBytes(), nameRoot,
@@ -212,6 +214,7 @@
   return new InitializedCompilerState(options, processedOpts,
       workerInputCache: workerInputCache,
       incrementalCompiler: incrementalCompiler,
+      tags: tags,
       libraryToInputDill: libraryToInputDill);
 }
 
diff --git a/pkg/front_end/lib/src/api_unstable/compiler_state.dart b/pkg/front_end/lib/src/api_unstable/compiler_state.dart
index 57fdac4..0852c60 100644
--- a/pkg/front_end/lib/src/api_unstable/compiler_state.dart
+++ b/pkg/front_end/lib/src/api_unstable/compiler_state.dart
@@ -16,11 +16,13 @@
   final ProcessedOptions processedOpts;
   final Map<Uri, WorkerInputComponent> workerInputCache;
   final IncrementalCompiler incrementalCompiler;
+  final Set<String> tags;
   final Map<Uri, Uri> libraryToInputDill;
 
   InitializedCompilerState(this.options, this.processedOpts,
       {this.workerInputCache,
       this.incrementalCompiler,
+      this.tags,
       this.libraryToInputDill});
 }
 
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index 547f79a..585c738 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -33,7 +33,7 @@
 import 'compiler_state.dart'
     show InitializedCompilerState, WorkerInputComponent, digestsEqual;
 
-import 'util.dart' show equalLists, equalMaps;
+import 'util.dart' show equalLists, equalMaps, equalSets;
 
 export '../api_prototype/compiler_options.dart'
     show CompilerOptions, parseExperimentalFlags, parseExperimentalArguments;
@@ -134,6 +134,7 @@
 
 Future<InitializedCompilerState> initializeIncrementalCompiler(
     InitializedCompilerState oldState,
+    Set<String> tags,
     List<Component> doneInputSummaries,
     bool compileSdk,
     Uri sdkRoot,
@@ -169,8 +170,9 @@
       cachedSdkInput == null ||
       !digestsEqual(cachedSdkInput.digest, sdkDigest) ||
       !equalMaps(oldState.options.experimentalFlags, experiments) ||
-      !equalMaps(oldState.options.environmentDefines, environmentDefines)) {
-    // No previous state.
+      !equalMaps(oldState.options.environmentDefines, environmentDefines) ||
+      !equalSets(oldState.tags, tags)) {
+    // No - or immediately not correct - previous state.
     options = new CompilerOptions()
       ..compileSdk = compileSdk
       ..sdkRoot = sdkRoot
@@ -265,7 +267,7 @@
       throw new StateError("Expected to get digest for $summary");
     }
     List<int> bytes = await fileSystem.entityForUri(summary).readAsBytes();
-    WorkerInputComponent cachedInput = WorkerInputComponent(
+    WorkerInputComponent cachedInput = new WorkerInputComponent(
         digest,
         await compilerState.processedOpts
             .loadComponent(bytes, nameRoot, alwaysCreateNewNamedNodes: true));
@@ -283,6 +285,7 @@
   return new InitializedCompilerState(options, processedOpts,
       workerInputCache: workerInputCache,
       incrementalCompiler: incrementalCompiler,
+      tags: tags,
       libraryToInputDill: libraryToInputDill);
 }
 
diff --git a/pkg/front_end/lib/src/api_unstable/util.dart b/pkg/front_end/lib/src/api_unstable/util.dart
index 146ddd0..cc5f7fc 100644
--- a/pkg/front_end/lib/src/api_unstable/util.dart
+++ b/pkg/front_end/lib/src/api_unstable/util.dart
@@ -12,6 +12,16 @@
   return true;
 }
 
+bool equalSets<K>(Set<K> a, Set<K> b) {
+  if (identical(a, b)) return true;
+  if (a == null || b == null) return false;
+  if (a.length != b.length) return false;
+  for (K entry in a) {
+    if (!b.contains(entry)) return false;
+  }
+  return true;
+}
+
 bool equalMaps<K, V>(Map<K, V> a, Map<K, V> b) {
   if (identical(a, b)) return true;
   if (a == null || b == null) return false;
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 47691d7..38dc042 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -40,19 +40,23 @@
     show
         LocatedMessage,
         messageBytecodeLimitExceededTooManyArguments,
+        messageFfiExceptionalReturnNull,
+        messageFfiExpectedConstant,
         noLength,
+        templateFfiDartTypeMismatch,
+        templateFfiExpectedExceptionalReturn,
+        templateFfiExpectedNoExceptionalReturn,
+        templateFfiExtendsOrImplementsSealedClass,
         templateFfiFieldAnnotation,
+        templateFfiFieldInitializer,
         templateFfiFieldNoAnnotation,
         templateFfiNotStatic,
+        templateFfiStructGeneric,
         templateFfiTypeInvalid,
         templateFfiTypeMismatch,
         templateFfiTypeUnsized,
-        templateFfiFieldInitializer,
-        templateIllegalRecursiveType,
-        templateFfiDartTypeMismatch,
-        templateFfiExtendsOrImplementsSealedClass,
-        templateFfiStructGeneric,
-        templateFfiWrongStructInheritance;
+        templateFfiWrongStructInheritance,
+        templateIllegalRecursiveType;
 
 export '../fasta/hybrid_file_system.dart' show HybridFileSystem;
 
diff --git a/pkg/front_end/lib/src/base/instrumentation.dart b/pkg/front_end/lib/src/base/instrumentation.dart
index 5c16ee9..7846749 100644
--- a/pkg/front_end/lib/src/base/instrumentation.dart
+++ b/pkg/front_end/lib/src/base/instrumentation.dart
@@ -10,7 +10,8 @@
     .replaceAll('→', '->')
     .replaceAll('dart.core::', '')
     .replaceAll('dart.async::', '')
-    .replaceAll('test::', '');
+    .replaceAll('test::', '')
+    .replaceAll(new RegExp(r'\s*/\*.*?\*/\s*'), '');
 
 /// Interface providing the ability to record property/value pairs associated
 /// with source file locations.  Intended to facilitate testing.
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index e1cb003..1f89337 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -306,6 +306,11 @@
   /// Whether to write a file (e.g. a dill file) when reporting a crash.
   bool get writeFileOnCrashReport => _raw.writeFileOnCrashReport;
 
+  /// The current sdk version string, e.g. "2.6.0-edge.sha1hash".
+  /// For instance used for language versioning (specifying the maximum
+  /// version).
+  String get currentSdkVersion => _raw.currentSdkVersion;
+
   Target _target;
   Target get target => _target ??=
       _raw.target ?? new NoneTarget(new TargetFlags(legacyMode: legacyMode));
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 285dc07..58fcf09 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -55,6 +55,8 @@
 
 export 'named_type_builder.dart' show NamedTypeBuilder;
 
+export 'nullability_builder.dart' show NullabilityBuilder;
+
 export 'prefix_builder.dart' show PrefixBuilder;
 
 export 'type_alias_builder.dart' show TypeAliasBuilder;
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 0e4d3a3..a673664 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
@@ -4,7 +4,7 @@
 
 library fasta.builtin_type_builder;
 
-import 'package:kernel/ast.dart' show DartType;
+import 'package:kernel/ast.dart' show DartType, Nullability;
 
 import 'builder.dart' show LibraryBuilder, TypeBuilder, TypeDeclarationBuilder;
 
@@ -15,11 +15,15 @@
       String name, this.type, LibraryBuilder compilationUnit, int charOffset)
       : super(null, 0, name, compilationUnit, charOffset);
 
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) =>
-      type;
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
+    // TODO(dmitryas): Use [nullability].
+    return type;
+  }
 
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
+    // TODO(dmitryas): Use [nullability].
     return type;
   }
 
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 6441675..481328b 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -21,6 +21,7 @@
         Member,
         MethodInvocation,
         Name,
+        Nullability,
         Procedure,
         ProcedureKind,
         RedirectingFactoryConstructor,
@@ -65,6 +66,8 @@
         TypeBuilder,
         TypeVariableBuilder;
 
+import 'declaration.dart';
+
 import 'declaration_builder.dart';
 
 import '../fasta_codes.dart'
@@ -80,8 +83,6 @@
         noLength,
         templateDuplicatedDeclarationUse,
         templateGenericFunctionTypeInferredAsActualTypeArgument,
-        templateIllegalMixinDueToConstructors,
-        templateIllegalMixinDueToConstructorsCause,
         templateImplementsRepeated,
         templateImplementsSuperClass,
         templateImplicitMixinOverrideContext,
@@ -100,6 +101,7 @@
         templateOverrideMoreRequiredArguments,
         templateOverrideTypeMismatchParameter,
         templateOverrideTypeMismatchReturnType,
+        templateOverrideTypeMismatchSetter,
         templateOverrideTypeVariablesMismatch,
         templateRedirectingFactoryIncompatibleTypeArgument,
         templateRedirectionTargetNotFound,
@@ -130,7 +132,7 @@
 import '../names.dart' show noSuchMethodName;
 
 import '../problems.dart'
-    show internalProblem, unexpected, unhandled, unimplemented;
+    show internalProblem, unexpected, unhandled, unimplemented, unsupported;
 
 import '../scope.dart' show AmbiguousBuilder;
 
@@ -201,7 +203,7 @@
     }
 
     MetadataBuilder.buildAnnotations(
-        isPatch ? origin.target : cls, metadata, library, this, null);
+        isPatch ? origin.cls : cls, metadata, library, this, null);
     constructors.forEach(build);
     scope.forEach(build);
   }
@@ -261,12 +263,12 @@
                   // be inferred.  Currently, the inference is not performed.
                   // The code below is a workaround.
                   typeArguments = new List<DartType>.filled(
-                      targetBuilder.target.enclosingClass.typeParameters.length,
+                      targetBuilder.member.enclosingClass.typeParameters.length,
                       const DynamicType(),
                       growable: true);
                 }
                 declaration.setRedirectingFactoryBody(
-                    targetBuilder.target, typeArguments);
+                    targetBuilder.member, typeArguments);
               } else if (targetBuilder is DillMemberBuilder) {
                 List<DartType> typeArguments = declaration.typeArguments;
                 if (typeArguments == null) {
@@ -274,7 +276,7 @@
                   // be inferred.  Currently, the inference is not performed.
                   // The code below is a workaround.
                   typeArguments = new List<DartType>.filled(
-                      targetBuilder.target.enclosingClass.typeParameters.length,
+                      targetBuilder.member.enclosingClass.typeParameters.length,
                       const DynamicType(),
                       growable: true);
                 }
@@ -351,10 +353,11 @@
   }
 
   @override
-  Builder lookupLocalMember(String name, {bool required: false}) {
-    Builder builder = scope.local[name];
+  Builder lookupLocalMember(String name,
+      {bool setter: false, bool required: false}) {
+    Builder builder = setter ? scope.setters[name] : scope.local[name];
     if (builder == null && isPatch) {
-      builder = origin.scope.local[name];
+      builder = setter ? origin.scope.setters[name] : origin.scope.local[name];
     }
     if (required && builder == null) {
       internalProblem(
@@ -382,9 +385,18 @@
     return declaration;
   }
 
+  /// The [Class] built by this builder.
+  ///
+  /// For a patch class the origin class is returned.
   Class get cls;
 
-  Class get target => cls;
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  UnrelatedTarget get target => unsupported(
+      "ClassBuilder.target is deprecated. "
+      "Use ClassBuilder.cls instead.",
+      charOffset,
+      fileUri);
 
   Class get actualCls;
 
@@ -395,10 +407,12 @@
   InterfaceType get thisType => cls.thisType;
 
   /// [arguments] have already been built.
-  InterfaceType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  InterfaceType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
     assert(arguments == null || cls.typeParameters.length == arguments.length);
-    return arguments == null ? cls.rawType : new InterfaceType(cls, arguments);
+    return arguments == null
+        ? cls.rawType
+        : new InterfaceType(cls, arguments, nullability);
   }
 
   @override
@@ -443,20 +457,21 @@
   }
 
   /// If [arguments] are null, the default types for the variables are used.
-  InterfaceType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+  InterfaceType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
     return buildTypesWithBuiltArguments(
-        library, buildTypeArguments(library, arguments));
+        library, nullability, buildTypeArguments(library, arguments));
   }
 
   Supertype buildSupertype(
       LibraryBuilder library, List<TypeBuilder> arguments) {
-    Class cls = isPatch ? origin.target : this.cls;
+    Class cls = isPatch ? origin.cls : this.cls;
     return new Supertype(cls, buildTypeArguments(library, arguments));
   }
 
   Supertype buildMixedInType(
       LibraryBuilder library, List<TypeBuilder> arguments) {
-    Class cls = isPatch ? origin.target : this.cls;
+    Class cls = isPatch ? origin.cls : this.cls;
     if (arguments != null) {
       return new Supertype(cls, buildTypeArguments(library, arguments));
     } else {
@@ -507,9 +522,9 @@
 
             problemsOffsets ??= new Map<ClassBuilder, int>();
             problemsOffsets[interface] ??= charOffset;
-          } else if (interface.target == coreTypes.futureOrClass) {
+          } else if (interface.cls == coreTypes.futureOrClass) {
             addProblem(messageImplementsFutureOr, charOffset,
-                interface.target.name.length);
+                interface.cls.name.length);
           } else {
             implemented.add(interface);
           }
@@ -651,7 +666,7 @@
   }
 
   void addRedirectingConstructor(
-      ProcedureBuilder constructor, SourceLibraryBuilder library) {
+      ProcedureBuilder constructorBuilder, SourceLibraryBuilder library) {
     // Add a new synthetic field to this class for representing factory
     // constructors. This is used to support resolving such constructors in
     // source code.
@@ -674,10 +689,10 @@
       cls.addMember(field);
       return new DillMemberBuilder(field, this);
     });
-    Field field = constructorsField.target;
+    Field field = constructorsField.member;
     ListLiteral literal = field.initializer;
     literal.expressions
-        .add(new StaticGet(constructor.target)..parent = literal);
+        .add(new StaticGet(constructorBuilder.procedure)..parent = literal);
   }
 
   void handleSeenCovariant(
@@ -1124,11 +1139,20 @@
       Message message;
       int fileOffset;
       if (declaredParameter == null) {
-        message = templateOverrideTypeMismatchReturnType.withArguments(
-            declaredMemberName,
-            declaredType,
-            interfaceType,
-            interfaceMemberName);
+        if (asIfDeclaredParameter) {
+          // Setter overridden by field
+          message = templateOverrideTypeMismatchSetter.withArguments(
+              declaredMemberName,
+              declaredType,
+              interfaceType,
+              interfaceMemberName);
+        } else {
+          message = templateOverrideTypeMismatchReturnType.withArguments(
+              declaredMemberName,
+              declaredType,
+              interfaceType,
+              interfaceMemberName);
+        }
         fileOffset = declaredMember.fileOffset;
       } else {
         message = templateOverrideTypeMismatchParameter.withArguments(
@@ -1418,26 +1442,6 @@
         : name;
   }
 
-  void checkMixinDeclaration() {
-    assert(cls.isMixinDeclaration);
-    for (Builder constructor in constructors.local.values) {
-      if (!constructor.isSynthetic &&
-          (constructor.isFactory || constructor.isConstructor)) {
-        addProblem(
-            templateIllegalMixinDueToConstructors
-                .withArguments(fullNameForErrors),
-            charOffset,
-            noLength,
-            context: [
-              templateIllegalMixinDueToConstructorsCause
-                  .withArguments(fullNameForErrors)
-                  .withLocation(
-                      constructor.fileUri, constructor.charOffset, noLength)
-            ]);
-      }
-    }
-  }
-
   void checkMixinApplication(ClassHierarchy hierarchy) {
     // A mixin declaration can only be applied to a class that implements all
     // the declaration's superclass constraints.
@@ -1540,7 +1544,7 @@
     }
 
     List<DartType> typeArguments =
-        getRedirectingFactoryBody(factory.target).typeArguments;
+        getRedirectingFactoryBody(factory.procedure).typeArguments;
     FunctionType targetFunctionType = target.functionType;
     if (typeArguments != null &&
         targetFunctionType.typeParameters.length != typeArguments.length) {
@@ -1665,7 +1669,7 @@
   ///
   /// It's an error if [superclass] isn't a superclass.
   Map<TypeParameter, DartType> getSubstitutionMap(Class superclass) {
-    Supertype supertype = target.supertype;
+    Supertype supertype = cls.supertype;
     Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
     List<DartType> arguments;
     List<TypeParameter> variables;
@@ -1785,8 +1789,8 @@
         builder = getSuperclass(builder)?.origin;
       }
       if (builder != null) {
-        Class target = builder.target;
-        for (Constructor constructor in target.constructors) {
+        Class cls = builder.cls;
+        for (Constructor constructor in cls.constructors) {
           if (constructor.name == name) return constructor;
         }
       }
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
index 107d2a5..e2c75dc 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration.dart
@@ -6,6 +6,9 @@
 
 import '../problems.dart' show unsupported;
 
+/// Dummy class to help deprecate [Builder.target].
+abstract class UnrelatedTarget {}
+
 abstract class Builder {
   /// Used when multiple things with the same name are declared within the same
   /// parent. Only used for top-level and class-member declarations, not for
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 6704c07..bc61309 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
@@ -48,7 +48,9 @@
 
   /// Lookups the member [name] declared in this declaration.
   ///
+  /// If [setter] is `true` the sought member is a setter or assignable field.
   /// If [required] is `true` and no member is found an internal problem is
   /// reported.
-  Builder lookupLocalMember(String name, {bool required: false});
+  Builder lookupLocalMember(String name,
+      {bool setter: false, bool required: false});
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 093e2f0..dcb82cb 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -4,7 +4,7 @@
 
 library fasta.enum_builder;
 
-import 'builder.dart' show ClassBuilder, MetadataBuilder;
+import 'builder.dart' show ClassBuilder, MetadataBuilder, NullabilityBuilder;
 
 import 'package:kernel/ast.dart'
     show
@@ -19,6 +19,7 @@
         IntLiteral,
         InterfaceType,
         ListLiteral,
+        Nullability,
         ProcedureKind,
         ReturnStatement,
         StaticGet,
@@ -107,15 +108,19 @@
     assert(enumConstantInfos == null || enumConstantInfos.isNotEmpty);
     // TODO(ahe): These types shouldn't be looked up in scope, they come
     // directly from dart:core.
-    TypeBuilder intType = new NamedTypeBuilder("int", null);
-    TypeBuilder stringType = new NamedTypeBuilder("String", null);
-    NamedTypeBuilder objectType = new NamedTypeBuilder("Object", null);
+    TypeBuilder intType =
+        new NamedTypeBuilder("int", const NullabilityBuilder.omitted(), null);
+    TypeBuilder stringType = new NamedTypeBuilder(
+        "String", const NullabilityBuilder.omitted(), null);
+    NamedTypeBuilder objectType = new NamedTypeBuilder(
+        "Object", const NullabilityBuilder.omitted(), null);
     Class cls = new Class(name: name);
     Map<String, MemberBuilder> members = <String, MemberBuilder>{};
     Map<String, MemberBuilder> constructors = <String, MemberBuilder>{};
-    NamedTypeBuilder selfType = new NamedTypeBuilder(name, null);
-    TypeBuilder listType =
-        new NamedTypeBuilder("List", <TypeBuilder>[selfType]);
+    NamedTypeBuilder selfType =
+        new NamedTypeBuilder(name, const NullabilityBuilder.omitted(), null);
+    TypeBuilder listType = new NamedTypeBuilder(
+        "List", const NullabilityBuilder.omitted(), <TypeBuilder>[selfType]);
 
     /// metadata class E {
     ///   final int index;
@@ -218,7 +223,7 @@
             enumConstantInfo.charOffset,
             enumConstantInfo.charOffset);
         metadataCollector?.setDocumentationComment(
-            fieldBuilder.target, documentationComment);
+            fieldBuilder.field, documentationComment);
         members[name] = fieldBuilder..next = existing;
       }
     }
@@ -227,9 +232,12 @@
     EnumBuilder enumBuilder = new EnumBuilder.internal(
         metadata,
         name,
-        new Scope(members, null, parent.scope, "enum $name",
+        new Scope(
+            local: members,
+            parent: parent.scope,
+            debugName: "enum $name",
             isModifiable: false),
-        new Scope(constructors, null, null, name, isModifiable: false),
+        new Scope(local: constructors, debugName: name, isModifiable: false),
         cls,
         enumConstantInfos,
         intType,
@@ -255,7 +263,9 @@
 
   TypeBuilder get mixedInType => null;
 
-  InterfaceType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+  InterfaceType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
+    // TODO(dmitryas): Use [nullability].
     return cls.rawType;
   }
 
@@ -316,7 +326,7 @@
           objectClass.charOffset, objectClass.name.length, objectClass.fileUri);
     } else {
       constructor.initializers.add(
-          new SuperInitializer(superConstructor.target, new Arguments.empty())
+          new SuperInitializer(superConstructor.member, new Arguments.empty())
             ..parent = constructor);
     }
     int index = 0;
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 d31fa16..8984604 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -6,15 +6,16 @@
 
 import 'package:kernel/ast.dart';
 
+import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
+import '../scope.dart';
+import '../problems.dart';
 import 'builder.dart';
+import 'declaration.dart';
 import 'declaration_builder.dart';
 import 'library_builder.dart';
 import 'metadata_builder.dart';
 import 'type_builder.dart';
 import 'type_variable_builder.dart';
-import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
-import '../scope.dart';
-import '../problems.dart';
 
 abstract class ExtensionBuilder extends DeclarationBuilder {
   final List<TypeVariableBuilder> typeParameters;
@@ -31,6 +32,9 @@
       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.
   Builder findStaticBuilder(
       String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
@@ -45,14 +49,23 @@
     return declaration;
   }
 
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  UnrelatedTarget get target => unsupported(
+      "ExtensionBuilder.target is deprecated. "
+      "Use ExtensionBuilder.extension instead.",
+      charOffset,
+      fileUri);
+
   @override
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
     throw new UnsupportedError("ExtensionBuilder.buildType is not supported.");
   }
 
   @override
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
     throw new UnsupportedError("ExtensionBuilder.buildTypesWithBuiltArguments "
         "is not supported.");
   }
@@ -64,9 +77,10 @@
   InterfaceType get thisType => null;
 
   @override
-  Builder lookupLocalMember(String name, {bool required: false}) {
+  Builder lookupLocalMember(String name,
+      {bool setter: false, bool required: false}) {
     // TODO(johnniwinther): Support patching on extensions.
-    Builder builder = scope.local[name];
+    Builder builder = setter ? scope.setters[name] : scope.local[name];
     if (required && builder == null) {
       internalProblem(
           templateInternalProblemNotFoundIn.withArguments(
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 91a427f..44bba27 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -9,7 +9,15 @@
 import 'builder.dart' show LibraryBuilder, MemberBuilder;
 
 import 'package:kernel/ast.dart'
-    show Class, DartType, Expression, Field, InvalidType, Name, NullLiteral;
+    show
+        Class,
+        DartType,
+        Expression,
+        Field,
+        InvalidType,
+        Member,
+        Name,
+        NullLiteral;
 
 import '../constant_context.dart' show ConstantContext;
 
@@ -42,7 +50,8 @@
 import '../type_inference/type_inference_engine.dart'
     show IncludesTypeParametersNonCovariantly, Variance;
 
-import '../type_inference/type_inferrer.dart' show TypeInferrerImpl;
+import '../type_inference/type_inferrer.dart'
+    show ExpressionInferenceResult, TypeInferrerImpl;
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
@@ -67,6 +76,8 @@
           ..fileEndOffset = charEndOffset,
         super(compilationUnit, charOffset);
 
+  Member get member => field;
+
   String get debugName => "FieldBuilder";
 
   bool get isField => true;
@@ -85,7 +96,7 @@
         (hasInitializer || isClassInstanceMember);
   }
 
-  Field build(SourceLibraryBuilder library) {
+  Field build(SourceLibraryBuilder libraryBuilder) {
     field
       ..isCovariant = isCovariant
       ..isFinal = isFinal
@@ -93,7 +104,7 @@
       ..isLate = isLate;
     if (isExtensionMember) {
       ExtensionBuilder extension = parent;
-      field.name = new Name('${extension.name}|$name', library.target);
+      field.name = new Name('${extension.name}|$name', libraryBuilder.library);
       field
         ..hasImplicitGetter = false
         ..hasImplicitSetter = false
@@ -101,7 +112,7 @@
         ..isExtensionMember = true;
     } else {
       // TODO(johnniwinther): How can the name already have been computed.
-      field.name ??= new Name(name, library.target);
+      field.name ??= new Name(name, libraryBuilder.library);
       bool isInstanceMember = !isStatic && !isTopLevel;
       field
         ..hasImplicitGetter = isInstanceMember
@@ -110,12 +121,13 @@
         ..isExtensionMember = false;
     }
     if (type != null) {
-      field.type = type.build(library);
+      field.type = type.build(libraryBuilder);
 
       if (!isFinal && !isConst) {
         IncludesTypeParametersNonCovariantly needsCheckVisitor;
         if (parent is ClassBuilder) {
-          Class enclosingClass = parent.target;
+          ClassBuilder enclosingClassBuilder = parent;
+          Class enclosingClass = enclosingClassBuilder.cls;
           if (enclosingClass.typeParameters.isNotEmpty) {
             needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
                 enclosingClass.typeParameters,
@@ -151,8 +163,9 @@
                 classBuilder.hasConstConstructor)) &&
         constInitializerToken != null) {
       Scope scope = classBuilder?.scope ?? library.scope;
-      BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
-          library, classBuilder, this, scope, fileUri);
+      BodyBuilder bodyBuilder = library.loader
+          .createBodyBuilderForOutlineExpression(
+              library, classBuilder, this, scope, fileUri);
       bodyBuilder.constantContext =
           isConst ? ConstantContext.inferred : ConstantContext.none;
       initializer = bodyBuilder.parseFieldInitializer(constInitializerToken)
@@ -169,8 +182,6 @@
     constInitializerToken = null;
   }
 
-  Field get target => field;
-
   @override
   void inferType() {
     SourceLibraryBuilder library = this.library;
@@ -197,16 +208,19 @@
     type.isStarted = true;
     TypeInferrerImpl typeInferrer = library.loader.typeInferenceEngine
         .createTopLevelTypeInferrer(
-            fileUri, field.enclosingClass?.thisType, null);
-    BodyBuilder bodyBuilder = new BodyBuilder.forField(this, typeInferrer);
+            fileUri, field.enclosingClass?.thisType, library);
+    BodyBuilder bodyBuilder =
+        library.loader.createBodyBuilderForField(this, typeInferrer);
     bodyBuilder.constantContext =
         isConst ? ConstantContext.inferred : ConstantContext.none;
     initializer = bodyBuilder.parseFieldInitializer(type.initializerToken);
     type.initializerToken = null;
 
-    DartType inferredType = typeInferrer.inferDeclarationType(typeInferrer
-        .inferExpression(field.initializer, const UnknownType(), true,
-            isVoidAllowed: true));
+    ExpressionInferenceResult result = typeInferrer.inferExpression(
+        field.initializer, const UnknownType(), true,
+        isVoidAllowed: true);
+    DartType inferredType =
+        typeInferrer.inferDeclarationType(result.inferredType);
 
     if (field.type is ImplicitFieldType) {
       // `field.type` may have changed if a circularity was detected when
@@ -215,7 +229,8 @@
 
       IncludesTypeParametersNonCovariantly needsCheckVisitor;
       if (parent is ClassBuilder) {
-        Class enclosingClass = parent.target;
+        ClassBuilder enclosingClassBuilder = parent;
+        Class enclosingClass = enclosingClassBuilder.cls;
         if (enclosingClass.typeParameters.isNotEmpty) {
           needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
               enclosingClass.typeParameters,
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 89fba82..4e7e8c3 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
@@ -60,7 +60,7 @@
   FormalParameterKind kind = FormalParameterKind.mandatory;
 
   /// The variable declaration created for this formal parameter.
-  VariableDeclaration declaration;
+  VariableDeclaration variable;
 
   /// The first token of the default value, if any.
   ///
@@ -94,12 +94,12 @@
   @override
   String get fullNameForErrors => name;
 
-  VariableDeclaration get target => declaration;
+  VariableDeclaration get target => variable;
 
   VariableDeclaration build(
       SourceLibraryBuilder library, int functionNestingLevel) {
-    if (declaration == null) {
-      declaration = new VariableDeclarationJudgment(name, functionNestingLevel,
+    if (variable == null) {
+      variable = new VariableDeclarationJudgment(name, functionNestingLevel,
           type: type?.build(library),
           isFinal: isFinal,
           isConst: isConst,
@@ -108,7 +108,7 @@
           isRequired: isNamedRequired)
         ..fileOffset = charOffset;
     }
-    return declaration;
+    return variable;
   }
 
   FormalParameterBuilder clone(List<TypeBuilder> newTypes) {
@@ -120,7 +120,7 @@
   }
 
   FormalParameterBuilder forFormalParameterInitializerScope() {
-    assert(declaration != null);
+    assert(variable != null);
     return !isInitializingFormal
         ? this
         : (new FormalParameterBuilder(
@@ -131,15 +131,15 @@
             null,
             charOffset)
           ..parent = parent
-          ..declaration = declaration);
+          ..variable = variable);
   }
 
   void finalizeInitializingFormal() {
     Object cls = parent.parent;
     if (cls is ClassBuilder) {
-      Builder field = cls.scope.lookup(name, charOffset, fileUri);
-      if (field is FieldBuilder) {
-        target.type = field.target.type;
+      Builder fieldBuilder = cls.scope.lookup(name, charOffset, fileUri);
+      if (fieldBuilder is FieldBuilder) {
+        variable.type = fieldBuilder.field.type;
       }
     }
   }
@@ -152,23 +152,27 @@
     // constant evaluation. Similarly we need to include initializers for
     // optional and named parameters of instance methods because these might be
     // needed to generated noSuchMethod forwarders.
-    final bool isConstConstructorParameter =
-        (parent is ConstructorBuilder && parent.target.isConst);
+    bool isConstConstructorParameter = false;
+    if (parent is ConstructorBuilder) {
+      ConstructorBuilder constructorBuilder = parent;
+      isConstConstructorParameter = constructorBuilder.constructor.isConst;
+    }
     if ((isConstConstructorParameter || parent.isClassInstanceMember) &&
         initializerToken != null) {
       final ClassBuilder classBuilder = parent.parent;
       Scope scope = classBuilder.scope;
-      BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
-          library, classBuilder, this, scope, fileUri);
+      BodyBuilder bodyBuilder = library.loader
+          .createBodyBuilderForOutlineExpression(
+              library, classBuilder, this, scope, fileUri);
       bodyBuilder.constantContext = ConstantContext.required;
-      target.initializer = bodyBuilder.parseFieldInitializer(initializerToken)
-        ..parent = target;
+      variable.initializer = bodyBuilder.parseFieldInitializer(initializerToken)
+        ..parent = variable;
       bodyBuilder.typeInferrer?.inferParameterInitializer(
-          bodyBuilder, target.initializer, target.type);
+          bodyBuilder, variable.initializer, variable.type);
       if (library.loader is SourceLoader) {
         SourceLoader loader = library.loader;
-        loader.transformPostInference(target, bodyBuilder.transformSetLiterals,
-            bodyBuilder.transformCollections);
+        loader.transformPostInference(variable,
+            bodyBuilder.transformSetLiterals, bodyBuilder.transformCollections);
       }
       bodyBuilder.resolveRedirectingFactoryTargets();
     }
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 52355e7..4e71b742 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
@@ -4,7 +4,7 @@
 
 library fasta.invalid_type_builder;
 
-import 'package:kernel/ast.dart' show DartType, InvalidType;
+import 'package:kernel/ast.dart' show DartType, InvalidType, Nullability;
 
 import '../fasta_codes.dart' show LocatedMessage;
 
@@ -28,13 +28,14 @@
   @override
   InvalidType get target => const InvalidType();
 
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
-    return buildTypesWithBuiltArguments(library, null);
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
+    return buildTypesWithBuiltArguments(library, null, null);
   }
 
   /// [Arguments] have already been built.
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
     if (!suppressMessage) {
       library.addProblem(message.messageObject, message.charOffset,
           message.length, message.uri,
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index d83d032..44d9beb 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -32,11 +32,14 @@
         FieldBuilder,
         ModifierBuilder,
         NameIterator,
+        NullabilityBuilder,
         PrefixBuilder,
         Scope,
         ScopeBuilder,
         TypeBuilder;
 
+import 'declaration.dart';
+
 abstract class LibraryBuilder extends ModifierBuilder {
   final Scope scope;
 
@@ -61,6 +64,14 @@
 
   bool get isSynthetic => false;
 
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  UnrelatedTarget get target => unsupported(
+      "LibraryBuilder.target is deprecated. "
+      "Use LibraryBuilder.library instead.",
+      charOffset,
+      fileUri);
+
   /// 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
@@ -91,13 +102,13 @@
   @override
   int get modifiers => 0;
 
-  @override
-  Library get target;
+  /// Returns the [Library] built by this builder.
+  Library get library;
 
   Uri get uri;
 
   Iterator<Builder> get iterator {
-    return LibraryLocalDeclarationIterator(this);
+    return new LibraryLocalDeclarationIterator(this);
   }
 
   NameIterator get nameIterator {
@@ -262,6 +273,19 @@
   void buildOutlineExpressions() {}
 
   List<FieldBuilder> takeImplicitlyTypedFields() => null;
+
+  // TODO(dmitryas): Compute the predicate using the library version instead.
+  bool get isNonNullableByDefault => loader.target.enableNonNullable;
+
+  NullabilityBuilder computeNullabilityFromToken(bool markedAsNullable) {
+    if (!isNonNullableByDefault) {
+      return const NullabilityBuilder.legacy();
+    }
+    if (markedAsNullable) {
+      return const NullabilityBuilder.nullable();
+    }
+    return const NullabilityBuilder.omitted();
+  }
 }
 
 class LibraryLocalDeclarationIterator implements Iterator<Builder> {
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 cc6877d..ddc7a64 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -4,11 +4,16 @@
 
 library fasta.member_builder;
 
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
 import '../problems.dart' show unsupported;
 
 import 'builder.dart'
     show ClassBuilder, Builder, LibraryBuilder, ModifierBuilder;
 
+import 'declaration.dart';
 import 'declaration_builder.dart';
 import 'extension_builder.dart';
 
@@ -53,12 +58,31 @@
     if (parent is LibraryBuilder) {
       LibraryBuilder library = parent;
       return library.partOfLibrary ?? library;
+    } else if (parent is ExtensionBuilder) {
+      ExtensionBuilder extension = parent;
+      return extension.library;
     } else {
       ClassBuilder cls = parent;
       return cls.library;
     }
   }
 
+  /// The [Member] built by this builder;
+  Member get member;
+
+  // TODO(johnniwinther): Deprecate this.
+  Member get target => member;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Member get extensionTearOff =>
+      unsupported("extensionTearOff", charOffset, fileUri);
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Procedure get procedure => unsupported("procedure", charOffset, fileUri);
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  ProcedureKind get kind => unsupported("kind", charOffset, fileUri);
+
   void buildOutlineExpressions(LibraryBuilder library) {}
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
index 5ac0dc0..cf5bbb6 100644
--- a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
@@ -34,8 +34,9 @@
     Scope scope = parent is Library || parent is Class || classBuilder == null
         ? library.scope
         : classBuilder.scope;
-    BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
-        library, classBuilder, member, scope, fileUri);
+    BodyBuilder bodyBuilder = library.loader
+        .createBodyBuilderForOutlineExpression(
+            library, classBuilder, member, scope, fileUri);
     for (int i = 0; i < metadata.length; ++i) {
       MetadataBuilder annotationBuilder = metadata[i];
       parent.addAnnotation(
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index b12233e..458013a 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -31,6 +31,7 @@
         Builder,
         Identifier,
         LibraryBuilder,
+        NullabilityBuilder,
         PrefixBuilder,
         QualifiedName,
         Scope,
@@ -54,12 +55,15 @@
 
   List<TypeBuilder> arguments;
 
+  final NullabilityBuilder nullabilityBuilder;
+
   @override
   TypeDeclarationBuilder declaration;
 
-  NamedTypeBuilder(this.name, this.arguments);
+  NamedTypeBuilder(this.name, this.nullabilityBuilder, this.arguments);
 
-  NamedTypeBuilder.fromTypeDeclarationBuilder(this.declaration,
+  NamedTypeBuilder.fromTypeDeclarationBuilder(
+      this.declaration, this.nullabilityBuilder,
       [this.arguments])
       : this.name = declaration.name;
 
@@ -181,6 +185,7 @@
       t.printOn(buffer);
     }
     buffer.write(">");
+    nullabilityBuilder.writeNullabilityOn(buffer);
     return buffer;
   }
 
@@ -209,7 +214,8 @@
 
   DartType build(LibraryBuilder library) {
     assert(declaration != null, "Declaration has not been resolved on $this.");
-    return declaration.buildType(library, arguments);
+    return declaration.buildType(
+        library, nullabilityBuilder.build(library), arguments);
   }
 
   Supertype buildSupertype(
@@ -248,7 +254,8 @@
     }
   }
 
-  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) {
+  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution,
+      [List<NamedTypeBuilder> unboundTypes]) {
     TypeBuilder result = substitution[declaration];
     if (result != null) {
       assert(declaration is TypeVariableBuilder);
@@ -257,7 +264,7 @@
       List<TypeBuilder> arguments;
       int i = 0;
       for (TypeBuilder argument in this.arguments) {
-        TypeBuilder type = argument.subst(substitution);
+        TypeBuilder type = argument.subst(substitution, unboundTypes);
         if (type != argument) {
           arguments ??= this.arguments.toList();
           arguments[i] = type;
@@ -265,7 +272,16 @@
         i++;
       }
       if (arguments != null) {
-        return new NamedTypeBuilder(name, arguments)..bind(declaration);
+        NamedTypeBuilder result =
+            new NamedTypeBuilder(name, nullabilityBuilder, arguments);
+        if (declaration != null) {
+          result.bind(declaration);
+        } else if (unboundTypes != null) {
+          unboundTypes.add(result);
+        } else {
+          throw new UnsupportedError("Unbound type in substitution: $result.");
+        }
+        return result;
       }
     }
     return this;
@@ -279,7 +295,8 @@
         clonedArguments[i] = arguments[i].clone(newTypes);
       }
     }
-    NamedTypeBuilder newType = new NamedTypeBuilder(name, clonedArguments);
+    NamedTypeBuilder newType =
+        new NamedTypeBuilder(name, nullabilityBuilder, clonedArguments);
     newTypes.add(newType);
     return newType;
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
new file mode 100644
index 0000000..dbe2ed7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide MapEntry;
+import 'package:kernel/ast.dart';
+import '../kernel/body_builder.dart';
+import '../builder/builder.dart';
+import '../problems.dart';
+
+/// Represents the nullability modifiers encountered while parsing the types.
+///
+/// The syntactic nullability needs to be interpreted, that is, built, into the
+/// semantic nullability used on [DartType]s of Kernel.
+enum SyntacticNullability {
+  /// Used when the type is declared with '?' suffix after it.
+  nullable,
+
+  /// Used when the type is declared in an opted-out library.
+  legacy,
+
+  /// Used when the type is declared without any nullability suffixes.
+  omitted,
+}
+
+class NullabilityBuilder {
+  final SyntacticNullability _syntacticNullability;
+
+  const NullabilityBuilder.nullable()
+      : _syntacticNullability = SyntacticNullability.nullable;
+
+  const NullabilityBuilder.legacy()
+      : _syntacticNullability = SyntacticNullability.legacy;
+
+  const NullabilityBuilder.omitted()
+      : _syntacticNullability = SyntacticNullability.omitted;
+
+  /// Used temporarily in the places that need proper handling of NNBD features.
+  ///
+  /// Over time the uses of [NullabilityBuilder.pendingImplementation] should be
+  /// eliminated, and the constructor should be eventually removed.  Currently,
+  /// it redirects to [NullabilityBuilder.legacy] as a conservative safety
+  /// measure for the pre-NNBD code and as a visible reminder of the feature
+  /// implementation being in progress in the NNBD code.
+  // TODO(dmitryas): Remove this constructor.
+  const NullabilityBuilder.pendingImplementation() : this.legacy();
+
+  Nullability build(LibraryBuilder libraryBuilder, {Nullability ifOmitted}) {
+    // TODO(dmitryas): Ensure that either ifOmitted is set or libraryBuilder is
+    // provided;
+    //assert(libraryBuilder != null || ifOmitted != null);
+    ifOmitted ??= (libraryBuilder == null ? Nullability.legacy : null);
+
+    ifOmitted ??= libraryBuilder.isNonNullableByDefault
+        ? Nullability.nonNullable
+        : Nullability.legacy;
+    switch (_syntacticNullability) {
+      case SyntacticNullability.legacy:
+        return Nullability.legacy;
+      case SyntacticNullability.nullable:
+        return Nullability.nullable;
+      case SyntacticNullability.omitted:
+        return ifOmitted;
+    }
+    return unhandled("$_syntacticNullability", "buildNullability",
+        TreeNode.noOffset, noLocation);
+  }
+
+  void writeNullabilityOn(StringBuffer sb) {
+    switch (_syntacticNullability) {
+      case SyntacticNullability.legacy:
+        sb.write("*");
+        return;
+      case SyntacticNullability.nullable:
+        sb.write("?");
+        return;
+      case SyntacticNullability.omitted:
+        // Do nothing.
+        return;
+    }
+    unhandled("$_syntacticNullability", "writeNullabilityOn", TreeNode.noOffset,
+        noLocation);
+  }
+}
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 6f97cf0..e39c9c2 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -4,13 +4,10 @@
 
 library fasta.procedure_builder;
 
-// Note: we're deliberately using AsyncMarker and ProcedureKind from kernel
-// outside the kernel-specific builders. This is simpler than creating
-// additional enums.
-import 'package:kernel/ast.dart'
-    show AsyncMarker, ProcedureKind, VariableDeclaration;
+import 'dart:core' hide MapEntry;
 
-import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
+import 'package:kernel/ast.dart';
+
 import 'package:kernel/type_algebra.dart';
 
 import 'builder.dart'
@@ -25,35 +22,7 @@
         TypeVariableBuilder;
 
 import 'extension_builder.dart';
-
-import 'package:kernel/ast.dart'
-    show
-        Arguments,
-        AsyncMarker,
-        Class,
-        Constructor,
-        ConstructorInvocation,
-        DartType,
-        DynamicType,
-        EmptyStatement,
-        Expression,
-        FunctionNode,
-        Initializer,
-        InterfaceType,
-        Member,
-        Name,
-        Procedure,
-        ProcedureKind,
-        RedirectingInitializer,
-        Statement,
-        StaticInvocation,
-        StringLiteral,
-        SuperInitializer,
-        TreeNode,
-        TypeParameter,
-        TypeParameterType,
-        VariableDeclaration,
-        setParents;
+import 'type_variable_builder.dart';
 
 import '../../scanner/token.dart' show Token;
 
@@ -171,7 +140,10 @@
         local[formal.name] = formal;
       }
     }
-    return new Scope(local, null, parent, "formal parameter",
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "formal parameter",
         isModifiable: false);
   }
 
@@ -196,7 +168,10 @@
     for (FormalParameterBuilder formal in formals) {
       local[formal.name] = formal.forFormalParameterInitializerScope();
     }
-    return new Scope(local, null, parent, "formal parameter initializer",
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "formal parameter initializer",
         isModifiable: false);
   }
 
@@ -209,7 +184,10 @@
     for (TypeVariableBuilder variable in typeVariables) {
       local[variable.name] = variable;
     }
-    return new Scope(local, null, parent, "type parameter",
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "type parameter",
         isModifiable: false);
   }
 
@@ -226,7 +204,7 @@
 
   FunctionNode function;
 
-  Statement actualBody;
+  Statement _body;
 
   FunctionBuilder get actualOrigin;
 
@@ -238,7 +216,7 @@
 //            newBody.fileOffset, fileUri);
 //      }
 //    }
-    actualBody = newBody;
+    _body = newBody;
     if (function != null) {
       // A forwarding semi-stub is a method that is abstract in the source code,
       // but which needs to have a forwarding stub body in order to ensure that
@@ -255,18 +233,18 @@
   }
 
   void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
-    if (actualBody != null) {
-      unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
+    if (_body != null) {
+      unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
     }
-    actualBody = new RedirectingFactoryBody(target, typeArguments);
-    function.body = actualBody;
-    actualBody?.parent = function;
+    _body = new RedirectingFactoryBody(target, typeArguments);
+    function.body = _body;
+    _body?.parent = function;
     if (isPatch) {
       actualOrigin.setRedirectingFactoryBody(target, typeArguments);
     }
   }
 
-  Statement get body => actualBody ??= new EmptyStatement();
+  Statement get body => _body ??= new EmptyStatement();
 
   bool get isNative => nativeMethodName != null;
 
@@ -275,7 +253,8 @@
     FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
     IncludesTypeParametersNonCovariantly needsCheckVisitor;
     if (!isConstructor && !isFactory && parent is ClassBuilder) {
-      Class enclosingClass = parent.target;
+      ClassBuilder enclosingClassBuilder = parent;
+      Class enclosingClass = enclosingClassBuilder.cls;
       if (enclosingClass.typeParameters.isNotEmpty) {
         needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
             enclosingClass.typeParameters,
@@ -335,7 +314,9 @@
     if (!isConstructor &&
         !isDeclarationInstanceMember &&
         parent is ClassBuilder) {
-      List<TypeParameter> typeParameters = parent.target.typeParameters;
+      ClassBuilder enclosingClassBuilder = parent;
+      List<TypeParameter> typeParameters =
+          enclosingClassBuilder.cls.typeParameters;
       if (typeParameters.isNotEmpty) {
         Map<TypeParameter, DartType> substitution;
         DartType removeTypeVariables(DartType type) {
@@ -403,7 +384,7 @@
   @override
   void buildOutlineExpressions(LibraryBuilder library) {
     MetadataBuilder.buildAnnotations(
-        target, metadata, library, isClassMember ? parent : null, this);
+        member, metadata, library, isClassMember ? parent : null, this);
 
     if (formals != null) {
       // For const constructors we need to include default parameter values
@@ -417,18 +398,18 @@
   }
 
   void becomeNative(Loader loader) {
-    Builder constructor = loader.getNativeAnnotation();
+    MemberBuilder constructor = loader.getNativeAnnotation();
     Arguments arguments =
         new Arguments(<Expression>[new StringLiteral(nativeMethodName)]);
     Expression annotation;
     if (constructor.isConstructor) {
-      annotation = new ConstructorInvocation(constructor.target, arguments)
+      annotation = new ConstructorInvocation(constructor.member, arguments)
         ..isConst = true;
     } else {
-      annotation = new StaticInvocation(constructor.target, arguments)
+      annotation = new StaticInvocation(constructor.member, arguments)
         ..isConst = true;
     }
-    target.addAnnotation(annotation);
+    member.addAnnotation(annotation);
   }
 
   bool checkPatch(FunctionBuilder patch) {
@@ -453,7 +434,7 @@
 }
 
 class ProcedureBuilder extends FunctionBuilder {
-  final Procedure procedure;
+  final Procedure _procedure;
   final int charOpenParenOffset;
   final ProcedureKind kind;
 
@@ -462,8 +443,14 @@
   @override
   ProcedureBuilder actualOrigin;
 
+  Procedure get actualProcedure => _procedure;
+
   bool hadTypesInferred = false;
 
+  /// If this is an extension instance method then [_extensionTearOff] holds
+  /// the synthetically created tear off function.
+  Procedure _extensionTearOff;
+
   ProcedureBuilder(
       List<MetadataBuilder> metadata,
       int modifiers,
@@ -478,7 +465,7 @@
       this.charOpenParenOffset,
       int charEndOffset,
       [String nativeMethodName])
-      : procedure =
+      : _procedure =
             new Procedure(null, kind, null, fileUri: compilationUnit?.fileUri)
               ..startFileOffset = startCharOffset
               ..fileOffset = charOffset
@@ -492,10 +479,64 @@
   AsyncMarker get asyncModifier => actualAsyncModifier;
 
   Statement get body {
-    if (actualBody == null && !isAbstract && !isExternal) {
-      actualBody = new EmptyStatement();
+    if (_body == null && !isAbstract && !isExternal) {
+      _body = new EmptyStatement();
     }
-    return actualBody;
+    return _body;
+  }
+
+  /// If this is an extension instance setter, wrap the setter body to return
+  /// the rhs value from the method.
+  ///
+  /// That is, this setter
+  ///
+  ///     extension E on A {
+  ///       void set property(B value) {
+  ///         value++;
+  ///       }
+  ///     }
+  ///
+  /// is converted into this top level method
+  ///
+  ///    B E|property(A #this, B value) {
+  ///      final #t1 = value;
+  ///      value++;
+  ///      return #t1;
+  ///    }
+  ///
+  void _updateExtensionSetterBody() {
+    if (isExtensionInstanceMember && isSetter) {
+      // TODO(johnniwinther): Avoid the synthetic variable if the parameter is
+      // never modified.
+      // TODO(johnniwinther): Handle setter bodies with return statements.
+      VariableDeclaration value = procedure.function.positionalParameters[1];
+      procedure.function.returnType = value.type;
+      Statement body = procedure.function.body;
+      List<Statement> statements = [];
+      Block block = new Block(statements);
+      VariableDeclaration variableDeclaration =
+          new VariableDeclarationJudgment.forValue(
+              new VariableGet(value)..fileOffset = procedure.fileOffset)
+            ..type = value.type;
+      statements.add(variableDeclaration);
+      if (body is Block) {
+        statements.addAll(body.statements);
+      } else {
+        statements.add(body);
+      }
+      ReturnStatement returnStatement = new ReturnStatement(
+          new VariableGet(variableDeclaration)
+            ..fileOffset = procedure.fileEndOffset);
+      statements.add(returnStatement);
+      setParents(block.statements, block);
+      procedure.function.body = block;
+      block.parent = procedure.function;
+    }
+  }
+
+  void set body(Statement newBody) {
+    super.body = newBody;
+    _updateExtensionSetterBody();
   }
 
   void set asyncModifier(AsyncMarker newModifier) {
@@ -525,18 +566,18 @@
     return parent is ExtensionBuilder;
   }
 
-  Procedure build(SourceLibraryBuilder library) {
+  Procedure build(SourceLibraryBuilder libraryBuilder) {
     // TODO(ahe): I think we may call this twice on parts. Investigate.
-    if (procedure.name == null) {
-      procedure.function = buildFunction(library);
-      procedure.function.parent = procedure;
-      procedure.function.fileOffset = charOpenParenOffset;
-      procedure.function.fileEndOffset = procedure.fileEndOffset;
-      procedure.isAbstract = isAbstract;
-      procedure.isExternal = isExternal;
-      procedure.isConst = isConst;
+    if (_procedure.name == null) {
+      _procedure.function = buildFunction(libraryBuilder);
+      _procedure.function.parent = _procedure;
+      _procedure.function.fileOffset = charOpenParenOffset;
+      _procedure.function.fileEndOffset = _procedure.fileEndOffset;
+      _procedure.isAbstract = isAbstract;
+      _procedure.isExternal = isExternal;
+      _procedure.isConst = isConst;
       if (isExtensionMethod) {
-        ExtensionBuilder extension = parent;
+        ExtensionBuilder extensionBuilder = parent;
         procedure.isExtensionMember = true;
         procedure.isStatic = true;
         String kindInfix = '';
@@ -560,17 +601,171 @@
           }
           procedure.kind = ProcedureKind.Method;
         }
-        procedure.name =
-            new Name('${extension.name}|${kindInfix}${name}', library.target);
+        procedure.name = new Name(
+            '${extensionBuilder.name}|${kindInfix}${name}',
+            libraryBuilder.library);
       } else {
-        procedure.isStatic = isStatic;
-        procedure.name = new Name(name, library.target);
+        _procedure.isStatic = isStatic;
+        _procedure.name = new Name(name, libraryBuilder.library);
       }
     }
-    return procedure;
+    if (extensionTearOff != null) {
+      _buildExtensionTearOff(libraryBuilder, parent);
+    }
+    return _procedure;
   }
 
-  Procedure get target => origin.procedure;
+  /// Creates a top level function that creates a tear off of an extension
+  /// instance method.
+  ///
+  /// For this declaration
+  ///
+  ///     extension E<T> on A<T> {
+  ///       X method<S>(S s, Y y) {}
+  ///     }
+  ///
+  /// we create the top level function
+  ///
+  ///     X E|method<T, S>(A<T> #this, S s, Y y) {}
+  ///
+  /// and the tear off function
+  ///
+  ///     X Function<S>(S, Y) E|get#method<T>(A<T> #this) {
+  ///       return (S s, Y y) => E|method<T, S>(#this, s, y);
+  ///     }
+  ///
+  void _buildExtensionTearOff(
+      SourceLibraryBuilder libraryBuilder, ExtensionBuilder extensionBuilder) {
+    assert(
+        _extensionTearOff != null, "No extension tear off created for $this.");
+    if (_extensionTearOff.name != null) return;
+
+    int fileOffset = _procedure.fileOffset;
+
+    int extensionTypeParameterCount =
+        extensionBuilder.typeParameters?.length ?? 0;
+
+    List<TypeParameter> typeParameters = <TypeParameter>[];
+
+    List<DartType> typeArguments = <DartType>[];
+    for (TypeParameter typeParameter in function.typeParameters) {
+      TypeParameter newTypeParameter = new TypeParameter(typeParameter.name);
+      typeParameters.add(newTypeParameter);
+      typeArguments.add(new TypeParameterType(newTypeParameter));
+    }
+
+    List<TypeParameter> tearOffTypeParameters = <TypeParameter>[];
+    List<TypeParameter> closureTypeParameters = <TypeParameter>[];
+    Substitution substitution =
+        Substitution.fromPairs(function.typeParameters, typeArguments);
+    for (int index = 0; index < typeParameters.length; index++) {
+      TypeParameter newTypeParameter = typeParameters[index];
+      newTypeParameter.bound =
+          substitution.substituteType(function.typeParameters[index].bound);
+      newTypeParameter.defaultType = function.typeParameters[index].defaultType;
+      if (index < extensionTypeParameterCount) {
+        tearOffTypeParameters.add(newTypeParameter);
+      } else {
+        closureTypeParameters.add(newTypeParameter);
+      }
+    }
+
+    VariableDeclaration copyParameter(
+        VariableDeclaration parameter, DartType type,
+        {bool isOptional}) {
+      // TODO(johnniwinther): Handle default values.
+      return new VariableDeclaration(parameter.name,
+          type: type,
+          initializer: isOptional ? new NullLiteral() : null,
+          isFinal: parameter.isFinal)
+        ..fileOffset = parameter.fileOffset;
+    }
+
+    VariableDeclaration extensionThis = copyParameter(
+        function.positionalParameters.first,
+        substitution.substituteType(function.positionalParameters.first.type),
+        isOptional: false);
+
+    DartType closureReturnType =
+        substitution.substituteType(function.returnType);
+    List<VariableDeclaration> closurePositionalParameters = [];
+    List<Expression> closurePositionalArguments = [];
+
+    for (int position = 0;
+        position < function.positionalParameters.length;
+        position++) {
+      VariableDeclaration parameter = function.positionalParameters[position];
+      if (position == 0) {
+        /// Pass `this` as a captured variable.
+        closurePositionalArguments
+            .add(new VariableGet(extensionThis)..fileOffset = fileOffset);
+      } else {
+        DartType type = substitution.substituteType(parameter.type);
+        VariableDeclaration newParameter = copyParameter(parameter, type,
+            isOptional: position >= function.requiredParameterCount);
+        closurePositionalParameters.add(newParameter);
+        closurePositionalArguments
+            .add(new VariableGet(newParameter)..fileOffset = fileOffset);
+      }
+    }
+    List<VariableDeclaration> closureNamedParameters = [];
+    List<NamedExpression> closureNamedArguments = [];
+    for (VariableDeclaration parameter in function.namedParameters) {
+      DartType type = substitution.substituteType(parameter.type);
+      VariableDeclaration newParameter =
+          copyParameter(parameter, type, isOptional: true);
+      closureNamedParameters.add(newParameter);
+      closureNamedArguments.add(new NamedExpression(parameter.name,
+          new VariableGet(newParameter)..fileOffset = fileOffset));
+    }
+
+    Statement closureBody = new ReturnStatement(
+        new StaticInvocation(
+            procedure,
+            new Arguments(closurePositionalArguments,
+                types: typeArguments, named: closureNamedArguments))
+          ..fileOffset = fileOffset)
+      ..fileOffset = fileOffset;
+
+    FunctionExpression closure = new FunctionExpression(new FunctionNode(
+        closureBody,
+        typeParameters: closureTypeParameters,
+        positionalParameters: closurePositionalParameters,
+        namedParameters: closureNamedParameters,
+        requiredParameterCount: procedure.function.requiredParameterCount - 1,
+        returnType: closureReturnType,
+        asyncMarker: procedure.function.asyncMarker,
+        dartAsyncMarker: procedure.function.dartAsyncMarker))
+      ..fileOffset = fileOffset;
+
+    _extensionTearOff
+      ..name = new Name(
+          '${extensionBuilder.name}|get#${name}', libraryBuilder.library)
+      ..function = new FunctionNode(
+          new ReturnStatement(closure)..fileOffset = fileOffset,
+          typeParameters: tearOffTypeParameters,
+          positionalParameters: [extensionThis],
+          requiredParameterCount: 1,
+          returnType: closure.function.functionType)
+      ..fileUri = fileUri
+      ..fileOffset = fileOffset;
+    _extensionTearOff.function.parent = _extensionTearOff;
+  }
+
+  /// The [Procedure] built by this builder.
+  Procedure get procedure => isPatch ? origin.procedure : _procedure;
+
+  /// If this is an extension instance method then [_extensionTearOff] holds
+  /// the synthetically created tear off function.
+  Procedure get extensionTearOff {
+    if (isExtensionInstanceMember && kind == ProcedureKind.Method) {
+      _extensionTearOff ??= new Procedure(null, ProcedureKind.Method, null,
+          isStatic: true, isExtensionMember: true);
+    }
+    return _extensionTearOff;
+  }
+
+  Member get member => procedure;
 
   @override
   int finishPatch() {
@@ -579,22 +774,22 @@
     // TODO(ahe): restore file-offset once we track both origin and patch file
     // URIs. See https://github.com/dart-lang/sdk/issues/31579
     origin.procedure.fileUri = fileUri;
-    origin.procedure.startFileOffset = procedure.startFileOffset;
-    origin.procedure.fileOffset = procedure.fileOffset;
-    origin.procedure.fileEndOffset = procedure.fileEndOffset;
+    origin.procedure.startFileOffset = _procedure.startFileOffset;
+    origin.procedure.fileOffset = _procedure.fileOffset;
+    origin.procedure.fileEndOffset = _procedure.fileEndOffset;
     origin.procedure.annotations
-        .forEach((m) => m.fileOffset = procedure.fileOffset);
+        .forEach((m) => m.fileOffset = _procedure.fileOffset);
 
-    origin.procedure.isAbstract = procedure.isAbstract;
-    origin.procedure.isExternal = procedure.isExternal;
-    origin.procedure.function = procedure.function;
+    origin.procedure.isAbstract = _procedure.isAbstract;
+    origin.procedure.isExternal = _procedure.isExternal;
+    origin.procedure.function = _procedure.function;
     origin.procedure.function.parent = origin.procedure;
     return 1;
   }
 
   @override
   void becomeNative(Loader loader) {
-    procedure.isExternal = true;
+    _procedure.isExternal = true;
     super.becomeNative(loader);
   }
 
@@ -612,7 +807,7 @@
 
 // TODO(ahe): Move this to own file?
 class ConstructorBuilder extends FunctionBuilder {
-  final Constructor constructor;
+  final Constructor _constructor;
 
   final int charOpenParenOffset;
 
@@ -627,6 +822,8 @@
   @override
   ConstructorBuilder actualOrigin;
 
+  Constructor get actualConstructor => _constructor;
+
   ConstructorBuilder(
       List<MetadataBuilder> metadata,
       int modifiers,
@@ -640,7 +837,7 @@
       this.charOpenParenOffset,
       int charEndOffset,
       [String nativeMethodName])
-      : constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
+      : _constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
           ..startFileOffset = startCharOffset
           ..fileOffset = charOffset
           ..fileEndOffset = charEndOffset,
@@ -663,7 +860,7 @@
   ProcedureKind get kind => null;
 
   bool get isRedirectingGenerativeConstructor {
-    return isRedirectingGenerativeConstructorImplementation(constructor);
+    return isRedirectingGenerativeConstructorImplementation(_constructor);
   }
 
   bool get isEligibleForTopLevelInference {
@@ -676,26 +873,27 @@
     return false;
   }
 
-  Constructor build(SourceLibraryBuilder library) {
-    if (constructor.name == null) {
-      constructor.function = buildFunction(library);
-      constructor.function.parent = constructor;
-      constructor.function.fileOffset = charOpenParenOffset;
-      constructor.function.fileEndOffset = constructor.fileEndOffset;
-      constructor.function.typeParameters = const <TypeParameter>[];
-      constructor.isConst = isConst;
-      constructor.isExternal = isExternal;
-      constructor.name = new Name(name, library.target);
+  Member build(SourceLibraryBuilder libraryBuilder) {
+    if (_constructor.name == null) {
+      _constructor.function = buildFunction(libraryBuilder);
+      _constructor.function.parent = _constructor;
+      _constructor.function.fileOffset = charOpenParenOffset;
+      _constructor.function.fileEndOffset = _constructor.fileEndOffset;
+      _constructor.function.typeParameters = const <TypeParameter>[];
+      _constructor.isConst = isConst;
+      _constructor.isExternal = isExternal;
+      _constructor.name = new Name(name, libraryBuilder.library);
     }
     if (isEligibleForTopLevelInference) {
       for (FormalParameterBuilder formal in formals) {
         if (formal.type == null && formal.isInitializingFormal) {
-          formal.declaration.type = null;
+          formal.variable.type = null;
         }
       }
-      library.loader.typeInferenceEngine.toBeInferred[constructor] = library;
+      libraryBuilder.loader.typeInferenceEngine.toBeInferred[_constructor] =
+          libraryBuilder;
     }
-    return constructor;
+    return _constructor;
   }
 
   @override
@@ -706,8 +904,9 @@
     // for const constructors into the outline.
     if (isConst && beginInitializers != null) {
       ClassBuilder classBuilder = parent;
-      BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
-          library, classBuilder, this, classBuilder.scope, fileUri);
+      BodyBuilder bodyBuilder = library.loader
+          .createBodyBuilderForOutlineExpression(
+              library, classBuilder, this, classBuilder.scope, fileUri);
       bodyBuilder.constantContext = ConstantContext.inferred;
       bodyBuilder.parseInitializers(beginInitializers);
       bodyBuilder.resolveRedirectingFactoryTargets();
@@ -719,22 +918,26 @@
     // According to the specification §9.3 the return type of a constructor
     // function is its enclosing class.
     FunctionNode functionNode = super.buildFunction(library);
-    ClassBuilder enclosingClass = parent;
+    ClassBuilder enclosingClassBuilder = parent;
+    Class enclosingClass = enclosingClassBuilder.cls;
     List<DartType> typeParameterTypes = new List<DartType>();
-    for (int i = 0; i < enclosingClass.target.typeParameters.length; i++) {
-      TypeParameter typeParameter = enclosingClass.target.typeParameters[i];
+    for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
+      TypeParameter typeParameter = enclosingClass.typeParameters[i];
       typeParameterTypes.add(new TypeParameterType(typeParameter));
     }
     functionNode.returnType =
-        new InterfaceType(enclosingClass.target, typeParameterTypes);
+        new InterfaceType(enclosingClass, typeParameterTypes);
     return functionNode;
   }
 
-  Constructor get target => origin.constructor;
+  /// The [Constructor] built by this builder.
+  Constructor get constructor => isPatch ? origin.constructor : _constructor;
+
+  Member get member => constructor;
 
   void injectInvalidInitializer(
       Message message, int charOffset, ExpressionGeneratorHelper helper) {
-    List<Initializer> initializers = constructor.initializers;
+    List<Initializer> initializers = _constructor.initializers;
     Initializer lastInitializer = initializers.removeLast();
     assert(lastInitializer == superInitializer ||
         lastInitializer == redirectingInitializer);
@@ -742,34 +945,34 @@
         helper.desugarSyntheticExpression(
             helper.buildProblem(message, charOffset, noLength)),
         charOffset);
-    initializers.add(error..parent = constructor);
+    initializers.add(error..parent = _constructor);
     initializers.add(lastInitializer);
   }
 
   void addInitializer(
       Initializer initializer, ExpressionGeneratorHelper helper) {
-    List<Initializer> initializers = constructor.initializers;
+    List<Initializer> initializers = _constructor.initializers;
     if (initializer is SuperInitializer) {
       if (superInitializer != null || redirectingInitializer != null) {
         injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
             initializer.fileOffset, helper);
       } else {
-        initializers.add(initializer..parent = constructor);
+        initializers.add(initializer..parent = _constructor);
         superInitializer = initializer;
       }
     } else if (initializer is RedirectingInitializer) {
       if (superInitializer != null || redirectingInitializer != null) {
         injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
             initializer.fileOffset, helper);
-      } else if (constructor.initializers.isNotEmpty) {
-        Initializer first = constructor.initializers.first;
+      } else if (_constructor.initializers.isNotEmpty) {
+        Initializer first = _constructor.initializers.first;
         Initializer error = helper.buildInvalidInitializer(
             helper.desugarSyntheticExpression(helper.buildProblem(
                 messageThisInitializerNotAlone, first.fileOffset, noLength)),
             first.fileOffset);
-        initializers.add(error..parent = constructor);
+        initializers.add(error..parent = _constructor);
       } else {
-        initializers.add(initializer..parent = constructor);
+        initializers.add(initializer..parent = _constructor);
         redirectingInitializer = initializer;
       }
     } else if (redirectingInitializer != null) {
@@ -779,7 +982,7 @@
       injectInvalidInitializer(
           messageSuperInitializerNotLast, superInitializer.fileOffset, helper);
     } else {
-      initializers.add(initializer..parent = constructor);
+      initializers.add(initializer..parent = _constructor);
     }
   }
 
@@ -790,23 +993,23 @@
     // TODO(ahe): restore file-offset once we track both origin and patch file
     // URIs. See https://github.com/dart-lang/sdk/issues/31579
     origin.constructor.fileUri = fileUri;
-    origin.constructor.startFileOffset = constructor.startFileOffset;
-    origin.constructor.fileOffset = constructor.fileOffset;
-    origin.constructor.fileEndOffset = constructor.fileEndOffset;
+    origin.constructor.startFileOffset = _constructor.startFileOffset;
+    origin.constructor.fileOffset = _constructor.fileOffset;
+    origin.constructor.fileEndOffset = _constructor.fileEndOffset;
     origin.constructor.annotations
-        .forEach((m) => m.fileOffset = constructor.fileOffset);
+        .forEach((m) => m.fileOffset = _constructor.fileOffset);
 
-    origin.constructor.isExternal = constructor.isExternal;
-    origin.constructor.function = constructor.function;
+    origin.constructor.isExternal = _constructor.isExternal;
+    origin.constructor.function = _constructor.function;
     origin.constructor.function.parent = origin.constructor;
-    origin.constructor.initializers = constructor.initializers;
+    origin.constructor.initializers = _constructor.initializers;
     setParents(origin.constructor.initializers, origin.constructor);
     return 1;
   }
 
   @override
   void becomeNative(Loader loader) {
-    constructor.isExternal = true;
+    _constructor.isExternal = true;
     super.becomeNative(loader);
   }
 
@@ -828,8 +1031,8 @@
     // again.
     // Note: this method clears both initializers from the target Kernel node
     // and internal state associated with parsing initializers.
-    if (target.isConst) {
-      target.initializers.length = 0;
+    if (constructor.isConst) {
+      constructor.initializers.length = 0;
       redirectingInitializer = null;
       superInitializer = null;
       hasMovedSuperInitializer = false;
@@ -871,12 +1074,12 @@
             nativeMethodName);
 
   @override
-  Statement get body => actualBody;
+  Statement get body => _body;
 
   @override
   void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
-    if (actualBody != null) {
-      unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
+    if (_body != null) {
+      unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
     }
 
     // Ensure that constant factories only have constant targets/bodies.
@@ -885,9 +1088,9 @@
           noLength, fileUri);
     }
 
-    actualBody = new RedirectingFactoryBody(target, typeArguments);
-    function.body = actualBody;
-    actualBody?.parent = function;
+    _body = new RedirectingFactoryBody(target, typeArguments);
+    function.body = _body;
+    _body?.parent = function;
     if (isPatch) {
       if (function.typeParameters != null) {
         Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
diff --git a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
index 3a151b4..35afd4b 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
@@ -10,6 +10,7 @@
         DynamicType,
         FunctionType,
         InvalidType,
+        Nullability,
         TypeParameter,
         Typedef,
         VariableDeclaration;
@@ -29,7 +30,7 @@
         TypeBuilder,
         TypeVariableBuilder;
 
-import '../problems.dart' show unhandled;
+import '../problems.dart' show unhandled, unsupported;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
@@ -41,32 +42,43 @@
         TypeDeclarationBuilder,
         TypeVariableBuilder;
 
+import 'declaration.dart';
+
 class TypeAliasBuilder extends TypeDeclarationBuilder {
   final TypeBuilder type;
 
   final List<TypeVariableBuilder> typeVariables;
 
-  final Typedef target;
+  /// The [Typedef] built by this builder.
+  final Typedef typedef;
 
   DartType thisType;
 
   TypeAliasBuilder(List<MetadataBuilder> metadata, String name,
       this.typeVariables, this.type, LibraryBuilder parent, int charOffset,
-      [Typedef target])
-      : target = target ??
+      [Typedef typedef])
+      : typedef = typedef ??
             (new Typedef(name, null,
                 typeParameters: TypeVariableBuilder.typeParametersFromBuilders(
                     typeVariables),
-                fileUri: parent.target.fileUri)
+                fileUri: parent.library.fileUri)
               ..fileOffset = charOffset),
         super(metadata, 0, name, parent, charOffset);
 
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  UnrelatedTarget get target => unsupported(
+      "TypeAliasBuilder.target is deprecated. "
+      "Use TypeAliasBuilder.typedef instead.",
+      charOffset,
+      fileUri);
+
   String get debugName => "TypeAliasBuilder";
 
   LibraryBuilder get parent => super.parent;
 
   Typedef build(SourceLibraryBuilder libraryBuilder) {
-    target..type ??= buildThisType(libraryBuilder);
+    typedef..type ??= buildThisType(libraryBuilder);
 
     TypeBuilder type = this.type;
     if (type is FunctionTypeBuilder) {
@@ -78,7 +90,7 @@
       }
       FreshTypeParameters freshTypeParameters =
           getFreshTypeParameters(typeParameters);
-      target.typeParametersOfFunctionType
+      typedef.typeParametersOfFunctionType
           .addAll(freshTypeParameters.freshTypeParameters);
 
       if (type.formals != null) {
@@ -86,9 +98,9 @@
           VariableDeclaration parameter = formal.build(libraryBuilder, 0);
           parameter.type = freshTypeParameters.substitute(parameter.type);
           if (formal.isNamed) {
-            target.namedParameters.add(parameter);
+            typedef.namedParameters.add(parameter);
           } else {
-            target.positionalParameters.add(parameter);
+            typedef.positionalParameters.add(parameter);
           }
         }
       }
@@ -96,7 +108,7 @@
       unhandled("${type.fullNameForErrors}", "build", charOffset, fileUri);
     }
 
-    return target;
+    return typedef;
   }
 
   DartType buildThisType(LibraryBuilder library) {
@@ -114,7 +126,7 @@
     thisType = cyclicTypeAliasMarker;
     TypeBuilder type = this.type;
     if (type is FunctionTypeBuilder) {
-      FunctionType builtType = type?.build(library, target.thisType);
+      FunctionType builtType = type?.build(library, typedef.thisType);
       if (builtType != null) {
         if (typeVariables != null) {
           for (TypeVariableBuilder tv in typeVariables) {
@@ -135,15 +147,16 @@
   }
 
   /// [arguments] have already been built.
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
+    // TODO(dmitryas): Use [nullability].
     DartType thisType = buildThisType(library);
     if (const DynamicType() == thisType) return thisType;
     FunctionType result = thisType;
-    if (target.typeParameters.isEmpty && arguments == null) return result;
+    if (typedef.typeParameters.isEmpty && arguments == null) return result;
     Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
-    for (int i = 0; i < target.typeParameters.length; i++) {
-      substitution[target.typeParameters[i]] = arguments[i];
+    for (int i = 0; i < typedef.typeParameters.length; i++) {
+      substitution[typedef.typeParameters[i]] = arguments[i];
     }
     return substitute(result, substitution);
   }
@@ -191,14 +204,15 @@
   int get typeVariablesCount => typeVariables?.length ?? 0;
 
   @override
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
     DartType thisType = buildThisType(library);
     if (thisType is InvalidType) return thisType;
     FunctionType result = thisType;
-    if (target.typeParameters.isEmpty && arguments == null) return result;
+    if (typedef.typeParameters.isEmpty && arguments == null) return result;
     // Otherwise, substitute.
     return buildTypesWithBuiltArguments(
-        library, buildTypeArguments(library, arguments));
+        library, nullability, buildTypeArguments(library, arguments));
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/builder/type_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
index 0c0b5f9..d3bf14f 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -8,8 +8,11 @@
 
 import '../fasta_codes.dart' show LocatedMessage;
 
-import 'builder.dart'
-    show LibraryBuilder, Scope, TypeDeclarationBuilder, TypeVariableBuilder;
+import '../scope.dart';
+import 'library_builder.dart';
+import 'named_type_builder.dart';
+import 'type_declaration_builder.dart';
+import 'type_variable_builder.dart';
 
 abstract class TypeBuilder {
   const TypeBuilder();
@@ -36,7 +39,18 @@
 
   String toString() => "$debugName(${printOn(new StringBuffer())})";
 
-  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) => this;
+  /// Returns the [TypeBuilder] for this type in which [TypeVariableBuilder]s
+  /// in [substitution] have been replaced by the corresponding [TypeBuilder]s.
+  ///
+  /// If [unboundTypes] is provided, created type builders that are not bound
+  /// are added to [unboundTypes]. Otherwise, creating an unbound type builder
+  /// throws an error.
+  // TODO(johnniwinther): Change [NamedTypeBuilder] to hold the
+  // [TypeParameterScopeBuilder] should resolve it, so that we cannot create
+  // [NamedTypeBuilder]s that are orphaned.
+  TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution,
+          [List<NamedTypeBuilder> unboundTypes]) =>
+      this;
 
   /// Clones the type builder recursively without binding the subterms to
   /// existing declaration or type variable builders.  All newly built types
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 fa2c7bd..e25faa6 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
@@ -4,7 +4,7 @@
 
 library fasta.type_declaration_builder;
 
-import 'package:kernel/ast.dart' show DartType;
+import 'package:kernel/ast.dart' show DartType, Nullability;
 
 import 'builder.dart'
     show Builder, LibraryBuilder, MetadataBuilder, ModifierBuilder, TypeBuilder;
@@ -31,9 +31,10 @@
 
   int get typeVariablesCount => 0;
 
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments);
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments);
 
   /// [arguments] have already been built.
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments);
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments);
 }
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 05f880f..bea9904 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,18 +4,27 @@
 
 library fasta.type_variable_builder;
 
-import 'builder.dart' show LibraryBuilder, TypeBuilder, TypeDeclarationBuilder;
+import 'builder.dart'
+    show
+        LibraryBuilder,
+        NullabilityBuilder,
+        TypeBuilder,
+        TypeDeclarationBuilder;
 
 import 'package:kernel/ast.dart'
-    show DartType, TypeParameter, TypeParameterType;
+    show DartType, Nullability, TypeParameter, TypeParameterType;
 
 import '../fasta_codes.dart' show templateTypeArgumentsOnTypeVariable;
 
 import '../kernel/kernel_builder.dart'
     show ClassBuilder, NamedTypeBuilder, LibraryBuilder, TypeBuilder;
 
+import '../problems.dart' show unsupported;
+
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
+import 'declaration.dart';
+
 class TypeVariableBuilder extends TypeDeclarationBuilder {
   TypeBuilder bound;
 
@@ -25,17 +34,21 @@
 
   TypeVariableBuilder actualOrigin;
 
+  final bool isExtensionTypeParameter;
+
   TypeVariableBuilder(
       String name, SourceLibraryBuilder compilationUnit, int charOffset,
-      {this.bound, bool synthesizeTypeParameterName: false})
-      : actualParameter = new TypeParameter(
-            synthesizeTypeParameterName ? '#$name' : name, null)
+      {this.bound, this.isExtensionTypeParameter: false})
+      : actualParameter = new TypeParameter(name, null)
           ..fileOffset = charOffset,
         super(null, 0, name, compilationUnit, charOffset);
 
   TypeVariableBuilder.fromKernel(
       TypeParameter parameter, LibraryBuilder compilationUnit)
       : actualParameter = parameter,
+        // TODO(johnniwinther): Do we need to support synthesized type
+        //  parameters from kernel?
+        this.isExtensionTypeParameter = false,
         super(null, 0, parameter.name, compilationUnit, parameter.fileOffset);
 
   bool get isTypeVariable => true;
@@ -55,11 +68,20 @@
 
   TypeVariableBuilder get origin => actualOrigin ?? this;
 
+  /// The [TypeParameter] built by this builder.
   TypeParameter get parameter => origin.actualParameter;
 
-  TypeParameter get target => parameter;
+  // Deliberately unrelated return type to statically detect more accidental
+  // uses until Builder.target is fully retired.
+  UnrelatedTarget get target => unsupported(
+      "TypeVariableBuilder.target is deprecated. "
+      "Use TypeVariableBuilder.parameter instead.",
+      charOffset,
+      fileUri);
 
-  DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+  DartType buildType(LibraryBuilder library, Nullability nullability,
+      List<TypeBuilder> arguments) {
+    // TODO(dmitryas): Use [nullability].
     if (arguments != null) {
       int charOffset = -1; // TODO(ahe): Provide these.
       Uri fileUri = null; // TODO(ahe): Provide these.
@@ -72,8 +94,8 @@
     return new TypeParameterType(parameter);
   }
 
-  DartType buildTypesWithBuiltArguments(
-      LibraryBuilder library, List<DartType> arguments) {
+  DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+      Nullability nullability, List<DartType> arguments) {
     if (arguments != null) {
       int charOffset = -1; // TODO(ahe): Provide these.
       Uri fileUri = null; // TODO(ahe): Provide these.
@@ -83,17 +105,20 @@
           name.length,
           fileUri);
     }
-    return buildType(library, null);
+    return buildType(library, nullability, null);
   }
 
   TypeBuilder asTypeBuilder() {
-    return new NamedTypeBuilder(name, null)..bind(this);
+    return new NamedTypeBuilder(
+        name, const NullabilityBuilder.pendingImplementation(), null)
+      ..bind(this);
   }
 
   void finish(
       LibraryBuilder library, ClassBuilder object, TypeBuilder dynamicType) {
     if (isPatch) return;
-    DartType objectType = object.buildType(library, null);
+    // TODO(dmitryas): Set the nullability of objectType correctly.
+    DartType objectType = object.buildType(library, Nullability.legacy, null);
     parameter.bound ??= bound?.build(library) ?? objectType;
     // If defaultType is not set, initialize it to dynamic, unless the bound is
     // explicitly specified as Object, in which case defaultType should also be
@@ -119,11 +144,11 @@
 
   @override
   bool operator ==(Object other) {
-    return other is TypeVariableBuilder && target == other.target;
+    return other is TypeVariableBuilder && parameter == other.parameter;
   }
 
   @override
-  int get hashCode => target.hashCode;
+  int get hashCode => parameter.hashCode;
 
   static List<TypeParameter> typeParametersFromBuilders(
       List<TypeVariableBuilder> builders) {
@@ -131,7 +156,7 @@
     List<TypeParameter> result =
         new List<TypeParameter>.filled(builders.length, null, growable: true);
     for (int i = 0; i < builders.length; i++) {
-      result[i] = builders[i].target;
+      result[i] = builders[i].parameter;
     }
     return result;
   }
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index 4aabb61..98d4be9 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -56,6 +56,8 @@
 
   Uri cachedSdkRoot = null;
 
+  bool compilingPlatform = false;
+
   CompilerContext(this.options);
 
   void disableColors() {
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 c7e42fe..eec951a 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
@@ -18,7 +18,7 @@
         Scope,
         TypeVariableBuilder;
 
-import '../modifier.dart' show abstractMask;
+import '../modifier.dart' show abstractMask, namedMixinApplicationMask;
 
 import 'dill_library_builder.dart' show DillLibraryBuilder;
 
@@ -37,9 +37,15 @@
             null,
             null,
             null,
-            new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
-                parent.scope, "class ${cls.name}", isModifiable: false),
-            new Scope(<String, MemberBuilder>{}, null, null, cls.name,
+            new Scope(
+                local: <String, MemberBuilder>{},
+                setters: <String, MemberBuilder>{},
+                parent: parent.scope,
+                debugName: "class ${cls.name}",
+                isModifiable: false),
+            new Scope(
+                local: <String, MemberBuilder>{},
+                debugName: cls.name,
                 isModifiable: false),
             parent,
             cls.fileOffset);
@@ -136,7 +142,14 @@
 }
 
 int computeModifiers(Class cls) {
-  return cls.isAbstract ? abstractMask : 0;
+  int modifiers = 0;
+  if (cls.isAbstract) {
+    modifiers |= abstractMask;
+  }
+  if (cls.isMixinApplication && cls.name != null) {
+    modifiers |= namedMixinApplicationMask;
+  }
+  return modifiers;
 }
 
 TypeBuilder computeTypeBuilder(
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
new file mode 100644
index 0000000..f0b1108
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
+import '../builder/extension_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../kernel/kernel_builder.dart';
+import '../scope.dart';
+
+import 'dill_class_builder.dart';
+import 'dill_extension_member_builder.dart';
+
+class DillExtensionBuilder extends ExtensionBuilder {
+  final Extension extension;
+  List<TypeVariableBuilder> _typeParameters;
+  TypeBuilder _onType;
+
+  DillExtensionBuilder(this.extension, LibraryBuilder parent)
+      : super(
+            null,
+            0,
+            extension.name,
+            parent,
+            extension.fileOffset,
+            new Scope(
+                local: <String, MemberBuilder>{},
+                setters: <String, MemberBuilder>{},
+                parent: parent.scope,
+                debugName: "extension ${extension.name}",
+                isModifiable: false),
+            null,
+            null) {
+    Map<Name, ExtensionMemberDescriptor> _methods = {};
+    Map<Name, Member> _tearOffs = {};
+    for (ExtensionMemberDescriptor descriptor in extension.members) {
+      Name name = descriptor.name;
+      switch (descriptor.kind) {
+        case ExtensionMemberKind.Method:
+          _methods[name] = descriptor;
+          break;
+        case ExtensionMemberKind.TearOff:
+          _tearOffs[name] = descriptor.member.asMember;
+          break;
+        case ExtensionMemberKind.Getter:
+        case ExtensionMemberKind.Operator:
+        case ExtensionMemberKind.Field:
+          Member member = descriptor.member.asMember;
+          scopeBuilder.addMember(name.name,
+              new DillExtensionMemberBuilder(member, descriptor, this));
+          break;
+        case ExtensionMemberKind.Setter:
+          Member member = descriptor.member.asMember;
+          scopeBuilder.addSetter(name.name,
+              new DillExtensionMemberBuilder(member, descriptor, this));
+          break;
+      }
+    }
+    _methods.forEach((Name name, ExtensionMemberDescriptor descriptor) {
+      Member member = descriptor.member.asMember;
+      scopeBuilder.addMember(
+          name.name,
+          new DillExtensionMemberBuilder(
+              member, descriptor, this, _tearOffs[name]));
+    });
+  }
+
+  @override
+  List<TypeVariableBuilder> get typeParameters {
+    if (_typeParameters == null && extension.typeParameters.isNotEmpty) {
+      _typeParameters =
+          computeTypeVariableBuilders(library, extension.typeParameters);
+    }
+    return _typeParameters;
+  }
+
+  @override
+  TypeBuilder get onType {
+    if (_onType == null) {
+      _onType = library.loader.computeTypeBuilder(extension.onType);
+    }
+    return _onType;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
new file mode 100644
index 0000000..b46cd36
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
+import '../builder/declaration.dart';
+
+import '../problems.dart';
+
+import 'dill_member_builder.dart';
+
+class DillExtensionMemberBuilder extends DillMemberBuilder {
+  final ExtensionMemberDescriptor _descriptor;
+
+  @override
+  final Member extensionTearOff;
+
+  DillExtensionMemberBuilder(Member member, this._descriptor, Builder parent,
+      [this.extensionTearOff])
+      : super(member, parent);
+
+  @override
+  bool get isStatic => _descriptor.isStatic;
+
+  @override
+  bool get isExternal => _descriptor.isExternal;
+
+  @override
+  Procedure get procedure {
+    switch (_descriptor.kind) {
+      case ExtensionMemberKind.Method:
+      case ExtensionMemberKind.Getter:
+      case ExtensionMemberKind.Operator:
+      case ExtensionMemberKind.Setter:
+        return member;
+      case ExtensionMemberKind.TearOff:
+      case ExtensionMemberKind.Field:
+    }
+    return unsupported("procedure", charOffset, fileUri);
+  }
+
+  @override
+  ProcedureKind get kind {
+    switch (_descriptor.kind) {
+      case ExtensionMemberKind.Method:
+        return ProcedureKind.Method;
+      case ExtensionMemberKind.Getter:
+        return ProcedureKind.Getter;
+      case ExtensionMemberKind.Operator:
+        return ProcedureKind.Operator;
+      case ExtensionMemberKind.Setter:
+        return ProcedureKind.Setter;
+      case ExtensionMemberKind.TearOff:
+      case ExtensionMemberKind.Field:
+    }
+    return null;
+  }
+}
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 f95d327..56c203ae 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
@@ -11,6 +11,7 @@
         Class,
         DartType,
         DynamicType,
+        Extension,
         Field,
         FunctionType,
         Library,
@@ -33,6 +34,12 @@
 
 import '../problems.dart' show internalProblem, unhandled, unimplemented;
 
+import '../builder/class_builder.dart';
+
+import '../builder/member_builder.dart';
+
+import '../builder/type_alias_builder.dart';
+
 import '../kernel/kernel_builder.dart'
     show Builder, DynamicTypeBuilder, InvalidTypeBuilder, LibraryBuilder, Scope;
 
@@ -40,6 +47,8 @@
 
 import 'dill_class_builder.dart' show DillClassBuilder;
 
+import 'dill_extension_builder.dart';
+
 import 'dill_member_builder.dart' show DillMemberBuilder;
 
 import 'dill_loader.dart' show DillLoader;
@@ -50,9 +59,13 @@
   DillLibraryBuilder libraryBuilder;
 
   LazyLibraryScope(Map<String, Builder> local, Map<String, Builder> setters,
-      Scope parent, String debugName,
-      {bool isModifiable: true})
-      : super(local, setters, parent, debugName, isModifiable: isModifiable);
+      Scope parent, String debugName, {bool isModifiable: true})
+      : super(
+            local: local,
+            setters: setters,
+            parent: parent,
+            debugName: debugName,
+            isModifiable: isModifiable);
 
   LazyLibraryScope.top({bool isModifiable: false})
       : this(<String, Builder>{}, <String, Builder>{}, null, "top",
@@ -72,6 +85,7 @@
 }
 
 class DillLibraryBuilder extends LibraryBuilder {
+  @override
   final Library library;
 
   DillLoader loader;
@@ -106,6 +120,7 @@
     if (isBuilt) return;
     isBuilt = true;
     library.classes.forEach(addClass);
+    library.extensions.forEach(addExtension);
     library.procedures.forEach(addMember);
     library.typedefs.forEach(addTypedef);
     library.fields.forEach(addMember);
@@ -131,9 +146,6 @@
   @override
   String get name => library.name;
 
-  @override
-  Library get target => library;
-
   void addSyntheticDeclarationOfDynamic() {
     addBuilder(
         "dynamic", new DynamicTypeBuilder(const DynamicType(), this, -1), -1);
@@ -156,6 +168,12 @@
     }
   }
 
+  void addExtension(Extension extension) {
+    DillExtensionBuilder extensionBuilder =
+        new DillExtensionBuilder(extension, this);
+    addBuilder(extension.name, extensionBuilder, extension.fileOffset);
+  }
+
   void addMember(Member member) {
     String name = member.name.name;
     if (name == "_exports#") {
@@ -298,7 +316,9 @@
             -1,
             fileUri);
       }
-      assert(node == declaration.target);
+      assert((declaration is ClassBuilder && node == declaration.cls) ||
+          (declaration is TypeAliasBuilder && node == declaration.typedef) ||
+          (declaration is MemberBuilder && node == declaration.member));
     }
   }
 }
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 1884cfc..4e04550 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
@@ -30,8 +30,6 @@
 
   String get debugName => "DillMemberBuilder";
 
-  Member get target => member;
-
   String get name => member.name.name;
 
   bool get isConstructor => member is Constructor;
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
index dce2cac..42b6dd1 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
@@ -28,7 +28,7 @@
   }
 
   @override
-  int get typeVariablesCount => target.typeParameters.length;
+  int get typeVariablesCount => typedef.typeParameters.length;
 
   @override
   FunctionTypeBuilder get type {
@@ -37,7 +37,7 @@
 
   @override
   DartType buildThisType(LibraryBuilder library) {
-    return thisType ??= target.type;
+    return thisType ??= typedef.type;
   }
 
   @override
@@ -48,10 +48,10 @@
     // [cls.typeParameters].
     if (arguments == null) {
       List<DartType> result = new List<DartType>.filled(
-          target.typeParameters.length, null,
+          typedef.typeParameters.length, null,
           growable: true);
       for (int i = 0; i < result.length; ++i) {
-        result[i] = target.typeParameters[i].defaultType;
+        result[i] = typedef.typeParameters[i].defaultType;
       }
       return result;
     }
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index cb27792..d5482bf 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -1719,6 +1719,14 @@
     message: r"""Null value during constant evaluation.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeConstEvalStartingPoint = messageConstEvalStartingPoint;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageConstEvalStartingPoint = const MessageCode(
+    "ConstEvalStartingPoint",
+    message: r"""Constant evaluation error:""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeConstEvalUnevaluated = messageConstEvalUnevaluated;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3300,6 +3308,47 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExplicitExtensionArgumentMismatch =
+    messageExplicitExtensionArgumentMismatch;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExplicitExtensionArgumentMismatch = const MessageCode(
+    "ExplicitExtensionArgumentMismatch",
+    message:
+        r"""Explicit extension application requires exactly 1 positional argument.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String name,
+        int
+            count)> templateExplicitExtensionTypeArgumentMismatch = const Template<
+        Message Function(String name, int count)>(
+    messageTemplate:
+        r"""Explicit extension application of extension '#name' takes '#count' type argument(s).""",
+    withArguments: _withArgumentsExplicitExtensionTypeArgumentMismatch);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name, int count)>
+    codeExplicitExtensionTypeArgumentMismatch =
+    const Code<Message Function(String name, int count)>(
+  "ExplicitExtensionTypeArgumentMismatch",
+  templateExplicitExtensionTypeArgumentMismatch,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsExplicitExtensionTypeArgumentMismatch(
+    String name, int count) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  if (count == null) throw 'No count provided';
+  return new Message(codeExplicitExtensionTypeArgumentMismatch,
+      message:
+          """Explicit extension application of extension '${name}' takes '${count}' type argument(s).""",
+      arguments: {'name': name, 'count': count});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeExportAfterPart = messageExportAfterPart;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3390,6 +3439,39 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresAbstractMember =
+    messageExtensionDeclaresAbstractMember;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresAbstractMember = const MessageCode(
+    "ExtensionDeclaresAbstractMember",
+    index: 94,
+    message: r"""Extensions can't declare abstract members.""",
+    tip: r"""Try providing an implementation for the member.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresConstructor =
+    messageExtensionDeclaresConstructor;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresConstructor = const MessageCode(
+    "ExtensionDeclaresConstructor",
+    index: 92,
+    message: r"""Extensions can't declare constructors.""",
+    tip: r"""Try removing the constructor declaration.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresInstanceField =
+    messageExtensionDeclaresInstanceField;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresInstanceField = const MessageCode(
+    "ExtensionDeclaresInstanceField",
+    index: 93,
+    message: r"""Extensions can't declare instance fields""",
+    tip: r"""Try removing the field declaration or making it a static field""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeExternalClass = messageExternalClass;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3673,6 +3755,81 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiExceptionalReturnNull = messageFfiExceptionalReturnNull;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiExceptionalReturnNull = const MessageCode(
+    "FfiExceptionalReturnNull",
+    message: r"""Exceptional return value must not be null.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiExpectedConstant = messageFfiExpectedConstant;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiExpectedConstant = const MessageCode(
+    "FfiExpectedConstant",
+    message: r"""Exceptional return value must be a constant.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        DartType
+            _type)> templateFfiExpectedExceptionalReturn = const Template<
+        Message Function(DartType _type)>(
+    messageTemplate:
+        r"""Expected an exceptional return value for a native callback returning '#type'.""",
+    withArguments: _withArgumentsFfiExpectedExceptionalReturn);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type)> codeFfiExpectedExceptionalReturn =
+    const Code<Message Function(DartType _type)>(
+  "FfiExpectedExceptionalReturn",
+  templateFfiExpectedExceptionalReturn,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiExpectedExceptionalReturn(DartType _type) {
+  TypeLabeler labeler = new TypeLabeler();
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFfiExpectedExceptionalReturn,
+      message:
+          """Expected an exceptional return value for a native callback returning '${type}'.""" +
+              labeler.originMessages,
+      arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        DartType
+            _type)> templateFfiExpectedNoExceptionalReturn = const Template<
+        Message Function(DartType _type)>(
+    messageTemplate:
+        r"""Exceptional return value cannot be provided for a native callback returning '#type'.""",
+    withArguments: _withArgumentsFfiExpectedNoExceptionalReturn);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type)>
+    codeFfiExpectedNoExceptionalReturn =
+    const Code<Message Function(DartType _type)>(
+  "FfiExpectedNoExceptionalReturn",
+  templateFfiExpectedNoExceptionalReturn,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiExpectedNoExceptionalReturn(DartType _type) {
+  TypeLabeler labeler = new TypeLabeler();
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFfiExpectedNoExceptionalReturn,
+      message:
+          """Exceptional return value cannot be provided for a native callback returning '${type}'.""" +
+              labeler.originMessages,
+      arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateFfiExtendsOrImplementsSealedClass =
     const Template<Message Function(String name)>(
@@ -3702,7 +3859,7 @@
     Message Function(String name)> templateFfiFieldAnnotation = const Template<
         Message Function(String name)>(
     messageTemplate:
-        r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
+        r"""Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
     withArguments: _withArgumentsFfiFieldAnnotation);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3718,7 +3875,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeFfiFieldAnnotation,
       message:
-          """Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
+          """Field '${name}' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
       arguments: {'name': name});
 }
 
@@ -3754,7 +3911,7 @@
             name)> templateFfiFieldNoAnnotation = const Template<
         Message Function(String name)>(
     messageTemplate:
-        r"""Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""",
+        r"""Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""",
     withArguments: _withArgumentsFfiFieldNoAnnotation);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3770,7 +3927,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeFfiFieldNoAnnotation,
       message:
-          """Field '${name}' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""",
+          """Field '${name}' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""",
       arguments: {'name': name});
 }
 
@@ -3779,7 +3936,7 @@
     Message Function(String name)> templateFfiNotStatic = const Template<
         Message Function(String name)>(
     messageTemplate:
-        r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
+        r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""",
     withArguments: _withArgumentsFfiNotStatic);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3795,7 +3952,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeFfiNotStatic,
       message:
-          """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
+          """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""",
       arguments: {'name': name});
 }
 
@@ -7061,6 +7218,15 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeMixinDeclaresConstructor = messageMixinDeclaresConstructor;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageMixinDeclaresConstructor = const MessageCode(
+    "MixinDeclaresConstructor",
+    index: 95,
+    message: r"""Mixins can't declare constructors.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         String name,
@@ -7971,6 +8137,54 @@
 const Template<
     Message Function(
         String name,
+        DartType _type,
+        DartType _type2,
+        String
+            name2)> templateOverrideTypeMismatchSetter = const Template<
+        Message Function(
+            String name, DartType _type, DartType _type2, String name2)>(
+    messageTemplate:
+        r"""The field '#name' has type '#type', which does not match the corresponding type, '#type2', in the overridden setter, '#name2'.""",
+    withArguments: _withArgumentsOverrideTypeMismatchSetter);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String name, DartType _type, DartType _type2, String name2)>
+    codeOverrideTypeMismatchSetter = const Code<
+            Message Function(
+                String name, DartType _type, DartType _type2, String name2)>(
+        "OverrideTypeMismatchSetter", templateOverrideTypeMismatchSetter,
+        analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsOverrideTypeMismatchSetter(
+    String name, DartType _type, DartType _type2, String name2) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler();
+  List<Object> typeParts = labeler.labelType(_type);
+  List<Object> type2Parts = labeler.labelType(_type2);
+  if (name2.isEmpty) throw 'No name provided';
+  name2 = demangleMixinApplicationName(name2);
+  String type = typeParts.join();
+  String type2 = type2Parts.join();
+  return new Message(codeOverrideTypeMismatchSetter,
+      message:
+          """The field '${name}' has type '${type}', which does not match the corresponding type, '${type2}', in the overridden setter, '${name2}'.""" +
+              labeler.originMessages,
+      arguments: {
+        'name': name,
+        'type': _type,
+        'type2': _type2,
+        'name2': name2
+      });
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String name,
         String
             name2)> templateOverrideTypeVariablesMismatch = const Template<
         Message Function(String name, String name2)>(
diff --git a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
index e90aab5..202fd66 100644
--- a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
+++ b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
@@ -4,39 +4,128 @@
 
 import 'package:meta/meta.dart';
 
-/// Sets of local variables that are potentially assigned in a loop statement,
-/// switch statement, try statement, or loop collection element.
-class AssignedVariables<StatementOrElement, Variable> {
-  final emptySet = Set<Variable>();
+/// [AssignedVariables] is a helper class capable of computing the set of
+/// variables that are potentially written to, and potentially captured by
+/// closures, at various locations inside the code being analyzed.  This class
+/// should be used prior to running flow analysis, to compute the sets of
+/// variables to pass in to flow analysis.
+///
+/// This class is intended to be used in two phases.  In the first phase, the
+/// client should traverse the source code recursively, making calls to
+/// [beginNode] and [endNode] to indicate the constructs in which writes should
+/// be tracked, and calls to [write] to indicate when a write is encountered.
+/// The order of visiting is not important provided that nesting is respected.
+/// This phase is called the "pre-traversal" because it should happen prior to
+/// flow analysis.
+///
+/// Then, in the second phase, the client may make queries using
+/// [capturedAnywhere], [writtenInNode], and [capturedInNode].
+///
+/// We use the term "node" to refer generally to a loop statement, switch
+/// statement, try statement, loop collection element, local function, or
+/// closure.
+class AssignedVariables<Node, Variable> {
+  /// Mapping from a node to the set of local variables that are potentially
+  /// written to within that node.
+  final Map<Node, Set<Variable>> _writtenInNode = {};
 
-  /// Mapping from a statement or element to the set of local variables that
-  /// are potentially assigned in that statement or element.
-  final Map<StatementOrElement, Set<Variable>> _map = {};
+  /// Mapping from a node to the set of local variables for which a potential
+  /// write is captured by a local function or closure inside that node.
+  final Map<Node, Set<Variable>> _capturedInNode = {};
 
-  /// The stack of nested statements or collection elements.
-  final List<Set<Variable>> _stack = [];
+  /// Set of local variables for which a potential write is captured by a local
+  /// function or closure anywhere in the code being analyzed.
+  final Set<Variable> _capturedAnywhere = {};
+
+  /// Stack of sets accumulating variables that are potentially written to.
+  ///
+  /// A set is pushed onto the stack when a node is entered, and popped when
+  /// a node is left.
+  final List<Set<Variable>> _writtenStack = [];
+
+  /// Stack of sets accumulating variables for which a potential write is
+  /// captured by a local function or closure.
+  ///
+  /// A set is pushed onto the stack when a node is entered, and popped when
+  /// a node is left.
+  final List<Set<Variable>> _capturedStack = [];
+
+  /// Stack of integers counting the number of entries in [_capturedStack] that
+  /// should be updated when a variable write is seen.
+  ///
+  /// When a closure is entered, the length of [_capturedStack] is pushed onto
+  /// this stack; when a node is left, it is popped.
+  ///
+  /// Each time a write occurs, we consult the top of this stack to determine
+  /// how many elements of [capturedStack] should be updated.
+  final List<int> _closureIndexStack = [];
 
   AssignedVariables();
 
-  /// Return the set of variables that are potentially assigned in the
-  /// [statementOrElement].
-  Set<Variable> operator [](StatementOrElement statementOrElement) {
-    return _map[statementOrElement] ?? emptySet;
-  }
+  /// Queries the set of variables for which a potential write is captured by a
+  /// local function or closure anywhere in the code being analyzed.
+  Set<Variable> get capturedAnywhere => _capturedAnywhere;
 
-  void beginStatementOrElement() {
-    Set<Variable> set = Set<Variable>.identity();
-    _stack.add(set);
-  }
-
-  void endStatementOrElement(StatementOrElement node) {
-    _map[node] = _stack.removeLast();
-  }
-
-  void write(Variable variable) {
-    for (int i = 0; i < _stack.length; ++i) {
-      _stack[i].add(variable);
+  /// This method should be called during pre-traversal, to mark the start of a
+  /// loop statement, switch statement, try statement, loop collection element,
+  /// local function, or closure which might need to be queried later.
+  ///
+  /// [isClosure] should be true if the node is a local function or closure.
+  ///
+  /// The span between the call to [beginNode] and [endNode] should cover any
+  /// statements and expressions that might be crossed by a backwards jump.  So
+  /// for instance, in a "for" loop, the condition, updaters, and body should be
+  /// covered, but the initializers should not.  Similarly, in a switch
+  /// statement, the body of the switch statement should be covered, but the
+  /// switch expression should not.
+  void beginNode({bool isClosure: false}) {
+    _writtenStack.add(new Set<Variable>.identity());
+    if (isClosure) {
+      _closureIndexStack.add(_capturedStack.length);
     }
+    _capturedStack.add(new Set<Variable>.identity());
+  }
+
+  /// Queries the set of variables for which a potential write is captured by a
+  /// local function or closure inside the [node].
+  Set<Variable> capturedInNode(Node node) {
+    return _capturedInNode[node] ?? const {};
+  }
+
+  /// This method should be called during pre-traversal, to mark the end of a
+  /// loop statement, switch statement, try statement, loop collection element,
+  /// local function, or closure which might need to be queried later.
+  ///
+  /// [isClosure] should be true if the node is a local function or closure.
+  ///
+  /// See [beginNode] for more details.
+  void endNode(Node node, {bool isClosure: false}) {
+    _writtenInNode[node] = _writtenStack.removeLast();
+    _capturedInNode[node] = _capturedStack.removeLast();
+    if (isClosure) {
+      _closureIndexStack.removeLast();
+    }
+  }
+
+  /// This method should be called during pre-traversal, to mark a write to a
+  /// variable.
+  void write(Variable variable) {
+    for (int i = 0; i < _writtenStack.length; ++i) {
+      _writtenStack[i].add(variable);
+    }
+    if (_closureIndexStack.isNotEmpty) {
+      _capturedAnywhere.add(variable);
+      int closureIndex = _closureIndexStack.last;
+      for (int i = 0; i < closureIndex; ++i) {
+        _capturedStack[i].add(variable);
+      }
+    }
+  }
+
+  /// Queries the set of variables that are potentially written to inside the
+  /// [node].
+  Set<Variable> writtenInNode(Node node) {
+    return _writtenInNode[node] ?? const {};
   }
 }
 
@@ -47,8 +136,6 @@
     return result;
   }
 
-  final _VariableSet<Variable> _emptySet;
-
   /// The [NodeOperations], used to manipulate expressions.
   final NodeOperations<Expression> nodeOperations;
 
@@ -92,30 +179,18 @@
   /// erroneous code, it's possible that a variable might be used before its
   /// declaration.
   final Set<Variable> _referencedVariables =
-      _assertionsEnabled ? Set<Variable>() : null;
+      _assertionsEnabled ? new Set<Variable>() : null;
 
   factory FlowAnalysis(
     NodeOperations<Expression> nodeOperations,
     TypeOperations<Variable, Type> typeOperations,
     FunctionBodyAccess<Variable> functionBody,
   ) {
-    _VariableSet<Variable> emptySet =
-        FlowModel<Variable, Type>(false).notAssigned;
-    return FlowAnalysis._(
-      nodeOperations,
-      typeOperations,
-      functionBody,
-      emptySet,
-    );
+    return new FlowAnalysis._(nodeOperations, typeOperations, functionBody);
   }
 
-  FlowAnalysis._(
-    this.nodeOperations,
-    this.typeOperations,
-    this.functionBody,
-    this._emptySet,
-  ) {
-    _current = FlowModel<Variable, Type>(true);
+  FlowAnalysis._(this.nodeOperations, this.typeOperations, this.functionBody) {
+    _current = new FlowModel<Variable, Type>(true);
   }
 
   /// Return `true` if the current state is reachable.
@@ -191,21 +266,20 @@
     }
 
     _condition = binaryExpression;
-    FlowModel<Variable, Type> currentPromoted =
+    FlowModel<Variable, Type> currentModel =
         _current.markNonNullable(typeOperations, variable);
     if (notEqual) {
-      _conditionTrue = currentPromoted;
+      _conditionTrue = currentModel;
       _conditionFalse = _current;
     } else {
       _conditionTrue = _current;
-      _conditionFalse = currentPromoted;
+      _conditionFalse = currentModel;
     }
   }
 
   void doStatement_bodyBegin(
-      Statement doStatement, Set<Variable> loopAssigned) {
-    _variablesReferenced(loopAssigned);
-    _current = _current.removePromotedAll(loopAssigned);
+      Statement doStatement, Iterable<Variable> loopAssigned) {
+    _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
 
     _statementToStackIndex[doStatement] = _stack.length;
     _stack.add(null); // break
@@ -235,8 +309,8 @@
   void finish() {
     assert(_stack.isEmpty);
     assert(() {
-      Set<Variable> variablesNotAdded =
-          _referencedVariables.difference(Set<Variable>.from(_addedVariables));
+      Set<Variable> variablesNotAdded = _referencedVariables
+          .difference(new Set<Variable>.from(_addedVariables));
       assert(variablesNotAdded.isEmpty,
           'Variables not passed to add: $variablesNotAdded');
       return true;
@@ -253,12 +327,21 @@
   ///
   /// [condition] is an opaque representation of the loop condition; it is
   /// matched against expressions passed to previous calls to determine whether
-  /// the loop condition should cause any promotions to occur.
+  /// the loop condition should cause any promotions to occur.  If [condition]
+  /// is null, the condition is understood to be empty (equivalent to a
+  /// condition of `true`).
   void for_bodyBegin(Statement node, Expression condition) {
-    _conditionalEnd(condition);
-    // Tail of the stack: falseCondition, trueCondition
+    FlowModel<Variable, Type> trueCondition;
+    if (condition == null) {
+      trueCondition = _current;
+      _stack.add(_current.setReachable(false));
+    } else {
+      _conditionalEnd(condition);
+      // Tail of the stack: falseCondition, trueCondition
 
-    FlowModel<Variable, Type> trueCondition = _stack.removeLast();
+      trueCondition = _stack.removeLast();
+    }
+    // Tail of the stack: falseCondition
 
     if (node != null) {
       _statementToStackIndex[node] = _stack.length;
@@ -290,8 +373,7 @@
   /// [loopAssigned] should be the set of variables that are assigned anywhere
   /// in the loop's condition, updaters, or body.
   void for_conditionBegin(Set<Variable> loopAssigned) {
-    _variablesReferenced(loopAssigned);
-    _current = _current.removePromotedAll(loopAssigned);
+    _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
   }
 
   /// Call this method just after visiting the updaters of a conventional "for"
@@ -327,9 +409,8 @@
   /// [loopAssigned] should be the set of variables that are assigned anywhere
   /// in the loop's body.
   void forEach_bodyBegin(Set<Variable> loopAssigned) {
-    _variablesReferenced(loopAssigned);
     _stack.add(_current);
-    _current = _current.removePromotedAll(loopAssigned);
+    _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
   }
 
   /// Call this method just before visiting the body of a "for-in" statement or
@@ -342,19 +423,19 @@
   void functionExpression_begin() {
     _stack.add(_current);
 
-    Set<Variable> notPromoted = null;
-    for (MapEntry<Variable, Type> entry in _current.promoted.entries) {
+    List<Variable> notPromoted = [];
+    for (MapEntry<Variable, VariableModel<Type>> entry
+        in _current.variableInfo.entries) {
       Variable variable = entry.key;
-      Type promotedType = entry.value;
+      Type promotedType = entry.value.promotedType;
       if (promotedType != null &&
           functionBody.isPotentiallyMutatedInScope(variable)) {
-        notPromoted ??= Set<Variable>.identity();
         notPromoted.add(variable);
       }
     }
 
-    if (notPromoted != null) {
-      _current = _current.removePromotedAll(notPromoted);
+    if (notPromoted.isNotEmpty) {
+      _current = _current.removePromotedAll(notPromoted, null);
     }
   }
 
@@ -425,7 +506,16 @@
   /// Return whether the [variable] is definitely assigned in the current state.
   bool isAssigned(Variable variable) {
     _variableReferenced(variable);
-    return !_current.notAssigned.contains(variable);
+    VariableModel<Type> variableInfo = _current.variableInfo[variable];
+    if (variableInfo == null) {
+      // In error-free code, variables should always be registered with flow
+      // analysis before they're used.  But this can't be relied on when the
+      // analyzer is doing error recovery.  So if we encounter a variable that
+      // hasn't been registered with flow analysis yet, assume it's unassigned.
+      return false;
+    } else {
+      return variableInfo.assigned;
+    }
   }
 
   void isExpression_end(
@@ -503,34 +593,56 @@
   /// is currently promoted.  Otherwise returns `null`.
   Type promotedType(Variable variable) {
     _variableReferenced(variable);
-    return _current.promoted[variable];
+    return _current.variableInfo[variable]?.promotedType;
   }
 
-  /// The [notPromoted] set contains all variables that are potentially
-  /// assigned in other cases that might target this with `continue`, so
-  /// these variables might have different types and are "un-promoted" from
-  /// the "afterExpression" state.
-  void switchStatement_beginCase(Set<Variable> notPromoted) {
-    _variablesReferenced(notPromoted);
-    _current = _stack.last.removePromotedAll(notPromoted);
-  }
-
-  void switchStatement_end(Statement switchStatement, bool hasDefault) {
-    // Tail of the stack: break, continue, afterExpression
-    FlowModel<Variable, Type> afterExpression = _current = _stack.removeLast();
-    _stack.removeLast(); // continue
-    FlowModel<Variable, Type> breakState = _stack.removeLast();
-
-    if (hasDefault) {
-      // breakState should not be null because we should have joined it with
-      // something non-null when handling the default case.
-      assert(breakState != null);
-      _current = breakState;
+  /// Call this method just before visiting one of the cases in the body of a
+  /// switch statement.  See [switchStatement_expressionEnd] for details.
+  ///
+  /// [hasLabel] indicates whether the case has any labels.
+  ///
+  /// The [notPromoted] set contains all variables that are potentially assigned
+  /// within the body of the switch statement.
+  void switchStatement_beginCase(
+      bool hasLabel, Iterable<Variable> notPromoted) {
+    if (hasLabel) {
+      _current =
+          _stack.last.removePromotedAll(notPromoted, _referencedVariables);
     } else {
-      _current = _join(breakState, afterExpression);
+      _current = _stack.last;
     }
   }
 
+  /// Call this method just after visiting the body of a switch statement.  See
+  /// [switchStatement_expressionEnd] for details.
+  ///
+  /// [hasDefault] indicates whether the switch statement had a "default" case.
+  void switchStatement_end(bool hasDefault) {
+    // Tail of the stack: break, continue, afterExpression
+    FlowModel<Variable, Type> afterExpression = _stack.removeLast();
+    _stack.removeLast(); // continue
+    FlowModel<Variable, Type> breakState = _stack.removeLast();
+
+    // It is allowed to "fall off" the end of a switch statement, so join the
+    // current state to any breaks that were found previously.
+    breakState = _join(breakState, _current);
+
+    // And, if there is an implicit fall-through default, join it to any breaks.
+    if (!hasDefault) breakState = _join(breakState, afterExpression);
+
+    _current = breakState;
+  }
+
+  /// Call this method just after visiting the expression part of a switch
+  /// statement.
+  ///
+  /// The order of visiting a switch statement should be:
+  /// - Visit the switch expression.
+  /// - Call [switchStatement_expressionEnd].
+  /// - For each switch case (including the default case, if any):
+  ///   - Call [switchStatement_beginCase].
+  ///   - Visit the case.
+  /// - Call [switchStatement_end].
   void switchStatement_expressionEnd(Statement switchStatement) {
     _statementToStackIndex[switchStatement] = _stack.length;
     _stack.add(null); // break
@@ -543,11 +655,10 @@
     // Tail of the stack: beforeBody
   }
 
-  void tryCatchStatement_bodyEnd(Set<Variable> assignedInBody) {
-    _variablesReferenced(assignedInBody);
+  void tryCatchStatement_bodyEnd(Iterable<Variable> assignedInBody) {
     FlowModel<Variable, Type> beforeBody = _stack.removeLast();
     FlowModel<Variable, Type> beforeCatch =
-        beforeBody.removePromotedAll(assignedInBody);
+        beforeBody.removePromotedAll(assignedInBody, _referencedVariables);
     _stack.add(beforeCatch);
     _stack.add(_current); // afterBodyAndCatches
     // Tail of the stack: beforeCatch, afterBodyAndCatches
@@ -576,20 +687,15 @@
   void tryFinallyStatement_end(Set<Variable> assignedInFinally) {
     _variablesReferenced(assignedInFinally);
     FlowModel<Variable, Type> afterBody = _stack.removeLast();
-    _current = _current.restrict(
-      typeOperations,
-      _emptySet,
-      afterBody,
-      assignedInFinally,
-    );
+    _current = _current.restrict(typeOperations, afterBody, assignedInFinally);
   }
 
-  void tryFinallyStatement_finallyBegin(Set<Variable> assignedInBody) {
-    _variablesReferenced(assignedInBody);
+  void tryFinallyStatement_finallyBegin(Iterable<Variable> assignedInBody) {
     FlowModel<Variable, Type> beforeTry = _stack.removeLast();
     FlowModel<Variable, Type> afterBody = _current;
     _stack.add(afterBody);
-    _current = _join(afterBody, beforeTry.removePromotedAll(assignedInBody));
+    _current = _join(afterBody,
+        beforeTry.removePromotedAll(assignedInBody, _referencedVariables));
   }
 
   void whileStatement_bodyBegin(
@@ -606,9 +712,8 @@
     _current = trueCondition;
   }
 
-  void whileStatement_conditionBegin(Set<Variable> loopAssigned) {
-    _variablesReferenced(loopAssigned);
-    _current = _current.removePromotedAll(loopAssigned);
+  void whileStatement_conditionBegin(Iterable<Variable> loopAssigned) {
+    _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
   }
 
   void whileStatement_end() {
@@ -622,7 +727,7 @@
   /// Register write of the given [variable] in the current state.
   void write(Variable variable) {
     _variableReferenced(variable);
-    _current = _current.write(typeOperations, _emptySet, variable);
+    _current = _current.write(typeOperations, variable);
   }
 
   void _conditionalEnd(Expression condition) {
@@ -672,23 +777,18 @@
   /// Indicates whether this point in the control flow is reachable.
   final bool reachable;
 
-  /// The set of variables that are not yet definitely assigned at this point in
-  /// the control flow.
-  final _VariableSet<Variable> notAssigned;
-
-  /// For each variable being tracked by flow analysis, the variable's promoted
-  /// type, or `null` if the variable's type is not promoted.
+  /// For each variable being tracked by flow analysis, the variable's model.
   ///
   /// Flow analysis has no awareness of scope, so variables that are out of
   /// scope are retained in the map until such time as their declaration no
   /// longer dominates the control flow.  So, for example, if a variable is
-  /// declared and then promoted inside the `then` branch of an `if` statement,
-  /// and the `else` branch of the `if` statement ends in a `return` statement,
-  /// then the variable remains in the map after the `if` statement ends, even
-  /// though the variable is not in scope anymore.  This should not have any
-  /// effect on analysis results for error-free code, because it is an error to
-  /// refer to a variable that is no longer in scope.
-  final Map<Variable, Type> promoted;
+  /// declared inside the `then` branch of an `if` statement, and the `else`
+  /// branch of the `if` statement ends in a `return` statement, then the
+  /// variable remains in the map after the `if` statement ends, even though the
+  /// variable is not in scope anymore.  This should not have any effect on
+  /// analysis results for error-free code, because it is an error to refer to a
+  /// variable that is no longer in scope.
+  final Map<Variable, VariableModel<Type> /*!*/ > variableInfo;
 
   /// Creates a state object with the given [reachable] status.  All variables
   /// are assumed to be unpromoted and already assigned, so joining another
@@ -696,30 +796,27 @@
   FlowModel(bool reachable)
       : this._(
           reachable,
-          _VariableSet<Variable>._(const []),
           const {},
         );
 
-  FlowModel._(
-    this.reachable,
-    this.notAssigned,
-    this.promoted,
-  );
+  FlowModel._(this.reachable, this.variableInfo) {
+    assert(() {
+      for (VariableModel<Type> value in variableInfo.values) {
+        assert(value != null);
+      }
+      return true;
+    }());
+  }
 
   /// Updates the state to track a newly declared local [variable].  The
   /// optional [assigned] boolean indicates whether the variable is assigned at
   /// the point of declaration.
   FlowModel<Variable, Type> add(Variable variable, {bool assigned: false}) {
-    _VariableSet<Variable> newNotAssigned =
-        assigned ? notAssigned : notAssigned.add(variable);
-    Map<Variable, Type> newPromoted = Map<Variable, Type>.from(promoted);
-    newPromoted[variable] = null;
+    Map<Variable, VariableModel<Type>> newVariableInfo =
+        new Map<Variable, VariableModel<Type>>.from(variableInfo);
+    newVariableInfo[variable] = new VariableModel<Type>(null, assigned);
 
-    return FlowModel<Variable, Type>._(
-      reachable,
-      newNotAssigned,
-      newPromoted,
-    );
+    return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
   }
 
   /// Updates the state to indicate that the given [variable] has been
@@ -729,21 +826,12 @@
   /// assigned?  Does it matter?
   FlowModel<Variable, Type> markNonNullable(
       TypeOperations<Variable, Type> typeOperations, Variable variable) {
-    Type previousType = promoted[variable];
+    VariableModel<Type> info = variableInfo[variable];
+    Type previousType = info.promotedType;
     previousType ??= typeOperations.variableType(variable);
     Type type = typeOperations.promoteToNonNull(previousType);
-
-    if (!typeOperations.isSameType(type, previousType)) {
-      Map<Variable, Type> newPromoted = <Variable, Type>{}..addAll(promoted);
-      newPromoted[variable] = type;
-      return FlowModel<Variable, Type>._(
-        reachable,
-        notAssigned,
-        newPromoted,
-      );
-    }
-
-    return this;
+    if (typeOperations.isSameType(type, previousType)) return this;
+    return _updateVariableInfo(variable, info.withPromotedType(type));
   }
 
   /// Updates the state to indicate that the given [variable] has been
@@ -760,26 +848,24 @@
     Variable variable,
     Type type,
   ) {
-    Type previousType = promoted[variable];
+    VariableModel<Type> info = variableInfo[variable];
+    Type previousType = info.promotedType;
     previousType ??= typeOperations.variableType(variable);
 
-    if (typeOperations.isSubtypeOf(type, previousType) &&
-        !typeOperations.isSameType(type, previousType)) {
-      Map<Variable, Type> newPromoted = <Variable, Type>{}..addAll(promoted);
-      newPromoted[variable] = type;
-      return FlowModel<Variable, Type>._(
-        reachable,
-        notAssigned,
-        newPromoted,
-      );
+    if (!typeOperations.isSubtypeOf(type, previousType) ||
+        typeOperations.isSameType(type, previousType)) {
+      return this;
     }
-
-    return this;
+    return _updateVariableInfo(variable, info.withPromotedType(type));
   }
 
   /// Updates the state to indicate that the given [variables] are no longer
   /// promoted; they are presumed to have their declared types.
   ///
+  /// If assertions are enabled and [referencedVariables] is not `null`, all
+  /// variables in [variables] will be stored in [referencedVariables] as a side
+  /// effect of this call.
+  ///
   /// This is used at the top of loops to conservatively cancel the promotion of
   /// variables that are modified within the loop, so that we correctly analyze
   /// code like the following:
@@ -796,16 +882,22 @@
   /// and only remove promotions if it can be shown that they aren't restored
   /// later in the loop body.  If we switch to a fixed point analysis, we should
   /// be able to remove this method.
-  FlowModel<Variable, Type> removePromotedAll(Set<Variable> variables) {
-    Map<Variable, Type> newPromoted = _removePromotedAll(promoted, variables);
-
-    if (identical(newPromoted, promoted)) return this;
-
-    return FlowModel<Variable, Type>._(
-      reachable,
-      notAssigned,
-      newPromoted,
-    );
+  FlowModel<Variable, Type> removePromotedAll(
+      Iterable<Variable> variables, Set<Variable> referencedVariables) {
+    Map<Variable, VariableModel<Type>> newVariableInfo;
+    for (Variable variable in variables) {
+      assert(() {
+        referencedVariables?.add(variable);
+        return true;
+      }());
+      VariableModel<Type> info = variableInfo[variable];
+      if (info?.promotedType != null) {
+        (newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
+            variableInfo))[variable] = info.withPromotedType(null);
+      }
+    }
+    if (newVariableInfo == null) return this;
+    return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
   }
 
   /// Updates the state to reflect a control path that is known to have
@@ -829,74 +921,37 @@
   /// block are considered "unsafe" because the assignment might have cancelled
   /// the effect of any promotion that occurred inside the `try` block.
   FlowModel<Variable, Type> restrict(
-    TypeOperations<Variable, Type> typeOperations,
-    _VariableSet<Variable> emptySet,
-    FlowModel<Variable, Type> other,
-    Set<Variable> unsafe,
-  ) {
+      TypeOperations<Variable, Type> typeOperations,
+      FlowModel<Variable, Type> other,
+      Set<Variable> unsafe) {
     bool newReachable = reachable && other.reachable;
-    _VariableSet<Variable> newNotAssigned = notAssigned.intersect(
-      empty: emptySet,
-      other: other.notAssigned,
-    );
-    if (newNotAssigned.variables.length == notAssigned.variables.length) {
-      newNotAssigned = notAssigned;
-    } else if (newNotAssigned.variables.length ==
-        other.notAssigned.variables.length) {
-      newNotAssigned = other.notAssigned;
-    }
 
-    Map<Variable, Type> newPromoted = <Variable, Type>{};
-    bool promotedMatchesThis = true;
-    bool promotedMatchesOther = other.promoted.length == promoted.length;
-    for (MapEntry<Variable, Type> entry in promoted.entries) {
+    Map<Variable, VariableModel<Type>> newVariableInfo =
+        <Variable, VariableModel<Type>>{};
+    bool variableInfoMatchesThis = true;
+    bool variableInfoMatchesOther =
+        other.variableInfo.length == variableInfo.length;
+    for (MapEntry<Variable, VariableModel<Type>> entry
+        in variableInfo.entries) {
       Variable variable = entry.key;
-      Type thisType = entry.value;
-      Type otherType = other.promoted[variable];
-      if (!unsafe.contains(variable)) {
-        if (otherType != null &&
-            (thisType == null ||
-                typeOperations.isSubtypeOf(otherType, thisType))) {
-          newPromoted[variable] = otherType;
-          if (promotedMatchesThis &&
-              (thisType == null ||
-                  !typeOperations.isSameType(thisType, otherType))) {
-            promotedMatchesThis = false;
-          }
-          continue;
-        }
-      }
-      if (thisType != null) {
-        newPromoted[variable] = thisType;
-        if (promotedMatchesOther &&
-            (otherType == null ||
-                !typeOperations.isSameType(thisType, otherType))) {
-          promotedMatchesOther = false;
-        }
-      } else {
-        newPromoted[variable] = null;
-        if (promotedMatchesOther && otherType != null) {
-          promotedMatchesOther = false;
-        }
-      }
+      VariableModel<Type> otherModel = other.variableInfo[variable];
+      VariableModel<Type> restricted = entry.value
+          .restrict(typeOperations, otherModel, unsafe.contains(variable));
+      newVariableInfo[variable] = restricted;
+      if (!identical(restricted, entry.value)) variableInfoMatchesThis = false;
+      if (!identical(restricted, otherModel)) variableInfoMatchesOther = false;
     }
-    assert(promotedMatchesThis ==
-        _promotionsEqual(typeOperations, newPromoted, promoted));
-    assert(promotedMatchesOther ==
-        _promotionsEqual(typeOperations, newPromoted, other.promoted));
-    if (promotedMatchesThis) {
-      newPromoted = promoted;
-    } else if (promotedMatchesOther) {
-      newPromoted = other.promoted;
+    assert(variableInfoMatchesThis ==
+        _variableInfosEqual(newVariableInfo, variableInfo));
+    assert(variableInfoMatchesOther ==
+        _variableInfosEqual(newVariableInfo, other.variableInfo));
+    if (variableInfoMatchesThis) {
+      newVariableInfo = variableInfo;
+    } else if (variableInfoMatchesOther) {
+      newVariableInfo = other.variableInfo;
     }
 
-    return _identicalOrNew(
-      this,
-      other,
-      newReachable,
-      newNotAssigned,
-      newPromoted,
-    );
+    return _identicalOrNew(this, other, newReachable, newVariableInfo);
   }
 
   /// Updates the state to indicate whether the control flow path is
@@ -904,78 +959,33 @@
   FlowModel<Variable, Type> setReachable(bool reachable) {
     if (this.reachable == reachable) return this;
 
-    return FlowModel<Variable, Type>._(
-      reachable,
-      notAssigned,
-      promoted,
-    );
+    return new FlowModel<Variable, Type>._(reachable, variableInfo);
   }
 
   @override
-  String toString() => '($reachable, $notAssigned, $promoted)';
+  String toString() => '($reachable, $variableInfo)';
 
   /// Updates the state to indicate that an assignment was made to the given
   /// [variable].  The variable is marked as definitely assigned, and any
   /// previous type promotion is removed.
   ///
   /// TODO(paulberry): allow for writes that preserve type promotions.
-  FlowModel<Variable, Type> write(TypeOperations<Variable, Type> typeOperations,
-      _VariableSet<Variable> emptySet, Variable variable) {
-    _VariableSet<Variable> newNotAssigned =
-        typeOperations.isLocalVariable(variable)
-            ? notAssigned.remove(emptySet, variable)
-            : notAssigned;
-
-    Map<Variable, Type> newPromoted = _removePromoted(promoted, variable);
-
-    if (identical(newNotAssigned, notAssigned) &&
-        identical(newPromoted, promoted)) {
-      return this;
-    }
-
-    return FlowModel<Variable, Type>._(
-      reachable,
-      newNotAssigned,
-      newPromoted,
-    );
+  FlowModel<Variable, Type> write(
+      TypeOperations<Variable, Type> typeOperations, Variable variable) {
+    VariableModel<Type> infoForVar = variableInfo[variable];
+    VariableModel<Type> newInfoForVar = infoForVar.write();
+    if (identical(newInfoForVar, infoForVar)) return this;
+    return _updateVariableInfo(variable, newInfoForVar);
   }
 
-  /// Removes a [variable] from a "promoted" [map], treating the map as
-  /// immutable.
-  Map<Variable, Type> _removePromoted(
-      Map<Variable, Type> map, Variable variable) {
-    if (map[variable] == null) return map;
-
-    Map<Variable, Type> result = Map<Variable, Type>.from(map);
-    result[variable] = null;
-    return result;
-  }
-
-  /// Removes a set of [variable]s from a "promoted" [map], treating the map as
-  /// immutable.
-  Map<Variable, Type> _removePromotedAll(
-    Map<Variable, Type> map,
-    Set<Variable> variables,
-  ) {
-    if (map.isEmpty) return const {};
-    if (variables.isEmpty) return map;
-
-    Map<Variable, Type> result = <Variable, Type>{};
-    bool noChanges = true;
-    for (MapEntry<Variable, Type> entry in map.entries) {
-      Variable variable = entry.key;
-      Type promotedType = entry.value;
-      if (variables.contains(variable) && promotedType != null) {
-        result[variable] = null;
-        noChanges = false;
-      } else {
-        result[variable] = promotedType;
-      }
-    }
-
-    if (noChanges) return map;
-    if (result.isEmpty) return const {};
-    return result;
+  /// Returns a new [FlowModel] where the information for [variable] is replaced
+  /// with [model].
+  FlowModel<Variable, Type> _updateVariableInfo(
+      Variable variable, VariableModel<Type> model) {
+    Map<Variable, VariableModel<Type>> newVariableInfo =
+        new Map<Variable, VariableModel<Type>>.from(variableInfo);
+    newVariableInfo[variable] = model;
+    return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
   }
 
   /// Forms a new state to reflect a control flow path that might have come from
@@ -999,59 +1009,39 @@
     if (!first.reachable && second.reachable) return second;
 
     bool newReachable = first.reachable || second.reachable;
-    _VariableSet<Variable> newNotAssigned =
-        first.notAssigned.union(second.notAssigned);
-    Map<Variable, Type> newPromoted =
-        FlowModel.joinPromoted(typeOperations, first.promoted, second.promoted);
+    Map<Variable, VariableModel<Type>> newVariableInfo =
+        FlowModel.joinVariableInfo(
+            typeOperations, first.variableInfo, second.variableInfo);
 
     return FlowModel._identicalOrNew(
-      first,
-      second,
-      newReachable,
-      newNotAssigned,
-      newPromoted,
-    );
+        first, second, newReachable, newVariableInfo);
   }
 
-  /// Joins two "promoted" maps.  See [join] for details.
+  /// Joins two "variable info" maps.  See [join] for details.
   @visibleForTesting
-  static Map<Variable, Type> joinPromoted<Variable, Type>(
+  static Map<Variable, VariableModel<Type>> joinVariableInfo<Variable, Type>(
     TypeOperations<Variable, Type> typeOperations,
-    Map<Variable, Type> first,
-    Map<Variable, Type> second,
+    Map<Variable, VariableModel<Type>> first,
+    Map<Variable, VariableModel<Type>> second,
   ) {
     if (identical(first, second)) return first;
     if (first.isEmpty || second.isEmpty) return const {};
 
-    Map<Variable, Type> result = <Variable, Type>{};
+    Map<Variable, VariableModel<Type>> result =
+        <Variable, VariableModel<Type>>{};
     bool alwaysFirst = true;
     bool alwaysSecond = true;
-    for (MapEntry<Variable, Type> entry in first.entries) {
+    for (MapEntry<Variable, VariableModel<Type>> entry in first.entries) {
       Variable variable = entry.key;
-      if (!second.containsKey(variable)) {
+      VariableModel<Type> secondModel = second[variable];
+      if (secondModel == null) {
         alwaysFirst = false;
       } else {
-        Type firstType = entry.value;
-        Type secondType = second[variable];
-        if (identical(firstType, secondType)) {
-          result[variable] = firstType;
-        } else if (firstType == null) {
-          result[variable] = null;
-          alwaysSecond = false;
-        } else if (secondType == null) {
-          result[variable] = null;
-          alwaysFirst = false;
-        } else if (typeOperations.isSubtypeOf(firstType, secondType)) {
-          result[variable] = secondType;
-          alwaysFirst = false;
-        } else if (typeOperations.isSubtypeOf(secondType, firstType)) {
-          result[variable] = firstType;
-          alwaysSecond = false;
-        } else {
-          result[variable] = null;
-          alwaysFirst = false;
-          alwaysSecond = false;
-        }
+        VariableModel<Type> joined =
+            VariableModel.join<Type>(typeOperations, entry.value, secondModel);
+        result[variable] = joined;
+        if (!identical(joined, entry.value)) alwaysFirst = false;
+        if (!identical(joined, secondModel)) alwaysSecond = false;
       }
     }
 
@@ -1064,45 +1054,36 @@
   /// Creates a new [FlowModel] object, unless it is equivalent to either
   /// [first] or [second], in which case one of those objects is re-used.
   static FlowModel<Variable, Type> _identicalOrNew<Variable, Type>(
-    FlowModel<Variable, Type> first,
-    FlowModel<Variable, Type> second,
-    bool newReachable,
-    _VariableSet<Variable> newNotAssigned,
-    Map<Variable, Type> newPromoted,
-  ) {
+      FlowModel<Variable, Type> first,
+      FlowModel<Variable, Type> second,
+      bool newReachable,
+      Map<Variable, VariableModel<Type>> newVariableInfo) {
     if (first.reachable == newReachable &&
-        identical(first.notAssigned, newNotAssigned) &&
-        identical(first.promoted, newPromoted)) {
+        identical(first.variableInfo, newVariableInfo)) {
       return first;
     }
     if (second.reachable == newReachable &&
-        identical(second.notAssigned, newNotAssigned) &&
-        identical(second.promoted, newPromoted)) {
+        identical(second.variableInfo, newVariableInfo)) {
       return second;
     }
 
-    return FlowModel<Variable, Type>._(
-      newReachable,
-      newNotAssigned,
-      newPromoted,
-    );
+    return new FlowModel<Variable, Type>._(newReachable, newVariableInfo);
   }
 
-  /// Determines whether the given "promoted" maps are equivalent.
-  static bool _promotionsEqual<Variable, Type>(
-      TypeOperations<Variable, Type> typeOperations,
-      Map<Variable, Type> p1,
-      Map<Variable, Type> p2) {
+  /// Determines whether the given "variableInfo" maps are equivalent.
+  ///
+  /// The equivalence check is shallow; if two variables' models are not
+  /// identical, we return `false`.
+  static bool _variableInfosEqual<Variable, Type>(
+      Map<Variable, VariableModel<Type>> p1,
+      Map<Variable, VariableModel<Type>> p2) {
     if (p1.length != p2.length) return false;
     if (!p1.keys.toSet().containsAll(p2.keys)) return false;
-    for (MapEntry<Variable, Type> entry in p1.entries) {
-      Type p1Value = entry.value;
-      Type p2Value = p2[entry.key];
-      if (p1Value == null) {
-        if (p2Value != null) return false;
-      } else {
-        if (p2Value == null) return false;
-        if (!typeOperations.isSameType(p1Value, p2Value)) return false;
+    for (MapEntry<Variable, VariableModel<Type>> entry in p1.entries) {
+      VariableModel<Type> p1Value = entry.value;
+      VariableModel<Type> p2Value = p2[entry.key];
+      if (!identical(p1Value, p2Value)) {
+        return false;
       }
     }
     return true;
@@ -1143,98 +1124,98 @@
   Type variableType(Variable variable);
 }
 
-/// List based immutable set of variables.
-class _VariableSet<Variable> {
-  final List<Variable> variables;
+/// An instance of the [VariableModel] class represents the information gathered
+/// by flow analysis for a single variable at a single point in the control flow
+/// of the function or method being analyzed.
+///
+/// Instances of this class are immutable, so the methods below that "update"
+/// the state actually leave `this` unchanged and return a new state object.
+@visibleForTesting
+class VariableModel<Type> {
+  /// The type that the variable has been promoted to, or `null` if the variable
+  /// is not promoted.
+  final Type promotedType;
 
-  _VariableSet._(this.variables);
+  /// Indicates whether the variable has definitely been assigned.
+  final bool assigned;
 
-  _VariableSet<Variable> add(Variable addedVariable) {
-    if (contains(addedVariable)) {
-      return this;
-    }
+  VariableModel(this.promotedType, this.assigned);
 
-    int length = variables.length;
-    List<Variable> newVariables = List<Variable>(length + 1);
-    for (int i = 0; i < length; ++i) {
-      newVariables[i] = variables[i];
-    }
-    newVariables[length] = addedVariable;
-    return _VariableSet._(newVariables);
+  @override
+  bool operator ==(Object other) {
+    return other is VariableModel<Type> &&
+        this.promotedType == other.promotedType &&
+        this.assigned == other.assigned;
   }
 
-  _VariableSet<Variable> addAll(Iterable<Variable> variables) {
-    _VariableSet<Variable> result = this;
-    for (Variable variable in variables) {
-      result = result.add(variable);
-    }
-    return result;
-  }
-
-  bool contains(Variable variable) {
-    int length = variables.length;
-    for (int i = 0; i < length; ++i) {
-      if (identical(variables[i], variable)) {
-        return true;
+  /// Returns an updated model reflect a control path that is known to have
+  /// previously passed through some [other] state.  See [FlowModel.restrict]
+  /// for details.
+  VariableModel<Type> restrict(TypeOperations<Object, Type> typeOperations,
+      VariableModel<Type> otherModel, bool unsafe) {
+    Type thisType = promotedType;
+    Type otherType = otherModel?.promotedType;
+    bool newAssigned = assigned || otherModel.assigned;
+    if (!unsafe) {
+      if (otherType != null &&
+          (thisType == null ||
+              typeOperations.isSubtypeOf(otherType, thisType))) {
+        return _identicalOrNew(this, otherModel, otherType, newAssigned);
       }
     }
-    return false;
-  }
-
-  _VariableSet<Variable> intersect({
-    _VariableSet<Variable> empty,
-    _VariableSet<Variable> other,
-  }) {
-    if (identical(other, empty)) return empty;
-    if (identical(this, other)) return this;
-
-    // TODO(scheglov) optimize
-    List<Variable> newVariables =
-        variables.toSet().intersection(other.variables.toSet()).toList();
-
-    if (newVariables.isEmpty) return empty;
-    return _VariableSet._(newVariables);
-  }
-
-  _VariableSet<Variable> remove(
-    _VariableSet<Variable> empty,
-    Variable removedVariable,
-  ) {
-    if (!contains(removedVariable)) {
-      return this;
-    }
-
-    int length = variables.length;
-    if (length == 1) {
-      return empty;
-    }
-
-    List<Variable> newVariables = List<Variable>(length - 1);
-    int newIndex = 0;
-    for (int i = 0; i < length; ++i) {
-      Variable variable = variables[i];
-      if (!identical(variable, removedVariable)) {
-        newVariables[newIndex++] = variable;
-      }
-    }
-
-    return _VariableSet._(newVariables);
+    return _identicalOrNew(this, otherModel, thisType, newAssigned);
   }
 
   @override
-  String toString() => variables.isEmpty ? '{}' : '{ ${variables.join(', ')} }';
+  String toString() => 'VariableModel($promotedType, $assigned)';
 
-  _VariableSet<Variable> union(_VariableSet<Variable> other) {
-    if (other.variables.isEmpty) {
-      return this;
-    }
+  /// Returns a new [VariableModel] where the promoted type is replaced with
+  /// [promotedType].
+  VariableModel<Type> withPromotedType(Type promotedType) =>
+      new VariableModel<Type>(promotedType, assigned);
 
-    _VariableSet<Variable> result = this;
-    List<Variable> otherVariables = other.variables;
-    for (int i = 0; i < otherVariables.length; ++i) {
-      Variable otherVariable = otherVariables[i];
-      result = result.add(otherVariable);
+  /// Returns a new [VariableModel] reflecting the fact that the variable was
+  /// just written to.
+  VariableModel<Type> write() {
+    if (promotedType == null && assigned) return this;
+    return new VariableModel<Type>(null, true);
+  }
+
+  /// Joins two variable models.  See [FlowModel.join] for details.
+  static VariableModel<Type> join<Type>(
+      TypeOperations<Object, Type> typeOperations,
+      VariableModel<Type> first,
+      VariableModel<Type> second) {
+    Type firstType = first.promotedType;
+    Type secondType = second.promotedType;
+    Type newPromotedType;
+    if (identical(firstType, secondType)) {
+      newPromotedType = firstType;
+    } else if (firstType == null || secondType == null) {
+      newPromotedType = null;
+    } else if (typeOperations.isSubtypeOf(firstType, secondType)) {
+      newPromotedType = secondType;
+    } else if (typeOperations.isSubtypeOf(secondType, firstType)) {
+      newPromotedType = firstType;
+    } else {
+      newPromotedType = null;
     }
-    return result;
+    bool newAssigned = first.assigned && second.assigned;
+    return _identicalOrNew(first, second, newPromotedType, newAssigned);
+  }
+
+  /// Creates a new [VariableModel] object, unless it is equivalent to either
+  /// [first] or [second], in which case one of those objects is re-used.
+  static VariableModel<Type> _identicalOrNew<Type>(VariableModel<Type> first,
+      VariableModel<Type> second, Type newPromotedType, bool newAssigned) {
+    if (identical(first.promotedType, newPromotedType) &&
+        first.assigned == newAssigned) {
+      return first;
+    } else if (identical(second.promotedType, newPromotedType) &&
+        second.assigned == newAssigned) {
+      return second;
+    } else {
+      return new VariableModel<Type>(newPromotedType, newAssigned);
+    }
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/import.dart b/pkg/front_end/lib/src/fasta/import.dart
index af6a7fb..437ec72 100644
--- a/pkg/front_end/lib/src/fasta/import.dart
+++ b/pkg/front_end/lib/src/fasta/import.dart
@@ -100,7 +100,7 @@
   if (prefix == null) return null;
   LibraryDependency dependency = null;
   if (deferred) {
-    dependency = new LibraryDependency.deferredImport(imported.target, prefix,
+    dependency = new LibraryDependency.deferredImport(imported.library, prefix,
         combinators: toKernelCombinators(combinators))
       ..fileOffset = charOffset;
   }
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 14a8d00..1288b94 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -48,7 +48,7 @@
 
 import '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
 
-import 'builder/builder.dart' show LibraryBuilder;
+import 'builder/builder.dart' show ClassBuilder, LibraryBuilder;
 
 import 'builder_graph.dart' show BuilderGraph;
 
@@ -248,7 +248,7 @@
 
         // Remove component problems for libraries we don't reuse.
         if (remainingComponentProblems.isNotEmpty) {
-          Library lib = builder.target;
+          Library lib = builder.library;
           removeLibraryFromRemainingComponentProblems(lib, uriTranslator);
         }
       }
@@ -256,7 +256,7 @@
       if (removedDillBuilders) {
         dillLoadedData.loader.libraries.clear();
         for (LibraryBuilder builder in dillLoadedData.loader.builders.values) {
-          dillLoadedData.loader.libraries.add(builder.target);
+          dillLoadedData.loader.libraries.add(builder.library);
         }
       }
 
@@ -282,7 +282,7 @@
       if (hierarchy != null) {
         List<Library> removedLibraries = new List<Library>();
         for (LibraryBuilder builder in notReusedLibraries) {
-          Library lib = builder.target;
+          Library lib = builder.library;
           removedLibraries.add(lib);
         }
         hierarchy.applyTreeChanges(removedLibraries, const []);
@@ -389,7 +389,7 @@
         allLibraries = outputLibraries.toSet();
         if (!c.options.omitPlatform) {
           for (int i = 0; i < platformBuilders.length; i++) {
-            Library lib = platformBuilders[i].target;
+            Library lib = platformBuilders[i].library;
             outputLibraries.add(lib);
           }
         }
@@ -503,7 +503,7 @@
     if (modulesToLoad != null && userBuilders != null) {
       Set<Library> loadedNotKept = new Set<Library>();
       for (LibraryBuilder builder in userBuilders.values) {
-        loadedNotKept.add(builder.target);
+        loadedNotKept.add(builder.library);
       }
       for (Component module in modulesToLoad) {
         loadedNotKept.removeAll(module.libraries);
@@ -651,13 +651,13 @@
 
     List<Uri> worklist = new List<Uri>();
     worklist.addAll(entries);
-    for (LibraryBuilder library in reusedLibraries) {
-      if (library.uri.scheme == "dart" && !library.isSynthetic) {
+    for (LibraryBuilder libraryBuilder in reusedLibraries) {
+      if (libraryBuilder.uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
         continue;
       }
-      Library lib = library.target;
-      potentiallyReferencedLibraries[library.uri] = lib;
-      libraryMap[library.uri] = lib;
+      Library lib = libraryBuilder.library;
+      potentiallyReferencedLibraries[libraryBuilder.uri] = lib;
+      libraryMap[libraryBuilder.uri] = lib;
     }
 
     LibraryGraph graph = new LibraryGraph(libraryMap);
@@ -683,7 +683,7 @@
       if (uri.scheme == "package") continue;
       LibraryBuilder builder = userCode.loader.builders.remove(uri);
       if (builder != null) {
-        Library lib = builder.target;
+        Library lib = builder.library;
         removedLibraries.add(lib);
         dillLoadedData.loader.builders.remove(uri);
         CompilerContext.current.uriToSource.remove(uri);
@@ -834,13 +834,14 @@
     assert(dillLoadedData != null && userCode != null);
 
     return await context.runInContext((_) async {
-      LibraryBuilder library =
+      LibraryBuilder libraryBuilder =
           userCode.loader.read(libraryUri, -1, accessor: userCode.loader.first);
 
-      Class kernelClass;
+      Class cls;
       if (className != null) {
-        kernelClass = library.scopeBuilder[className]?.target;
-        if (kernelClass == null) return null;
+        ClassBuilder classBuilder = libraryBuilder.scopeBuilder[className];
+        cls = classBuilder?.cls;
+        if (cls == null) return null;
       }
 
       userCode.loader.seenMessages.clear();
@@ -857,12 +858,16 @@
         debugExprUri,
         userCode.loader,
         null,
-        scope: library.scope.createNestedScope("expression"),
-        nameOrigin: library.target,
+        scope: libraryBuilder.scope.createNestedScope("expression"),
+        nameOrigin: libraryBuilder.library,
       );
+      debugLibrary.setLanguageVersion(
+          libraryBuilder.library.languageVersionMajor,
+          libraryBuilder.library.languageVersionMinor);
 
-      if (library is DillLibraryBuilder) {
-        for (LibraryDependency dependency in library.target.dependencies) {
+      if (libraryBuilder is DillLibraryBuilder) {
+        for (LibraryDependency dependency
+            in libraryBuilder.library.dependencies) {
           if (!dependency.isImport) continue;
 
           List<Combinator> combinators;
@@ -871,10 +876,10 @@
             combinators ??= <Combinator>[];
 
             combinators.add(combinator.isShow
-                ? new Combinator.show(
-                    combinator.names, combinator.fileOffset, library.fileUri)
-                : new Combinator.hide(
-                    combinator.names, combinator.fileOffset, library.fileUri));
+                ? new Combinator.show(combinator.names, combinator.fileOffset,
+                    libraryBuilder.fileUri)
+                : new Combinator.hide(combinator.names, combinator.fileOffset,
+                    libraryBuilder.fileUri));
           }
 
           debugLibrary.addImport(
@@ -915,13 +920,13 @@
         ..parent = parameters;
 
       procedure.fileUri = debugLibrary.fileUri;
-      procedure.parent = className != null ? kernelClass : library.target;
+      procedure.parent = className != null ? cls : libraryBuilder.library;
 
       userCode.uriToSource.remove(debugExprUri);
       userCode.loader.sourceBytes.remove(debugExprUri);
 
       // Make sure the library has a canonical name.
-      Component c = new Component(libraries: [debugLibrary.target]);
+      Component c = new Component(libraries: [debugLibrary.library]);
       c.computeCanonicalNames();
 
       userCode.runProcedureTransformations(procedure);
@@ -972,31 +977,31 @@
       return false;
     }
 
-    addBuilderAndInvalidateUris(Uri uri, LibraryBuilder library) {
-      if (uri.scheme == "dart" && !library.isSynthetic) {
-        result.add(library);
+    addBuilderAndInvalidateUris(Uri uri, LibraryBuilder libraryBuilder) {
+      if (uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
+        result.add(libraryBuilder);
         return;
       }
-      builders[uri] = library;
-      if (isInvalidated(uri, library.target.fileUri)) {
+      builders[uri] = libraryBuilder;
+      if (isInvalidated(uri, libraryBuilder.library.fileUri)) {
         invalidatedImportUris.add(uri);
       }
-      if (library is SourceLibraryBuilder) {
-        for (LibraryBuilder part in library.parts) {
+      if (libraryBuilder is SourceLibraryBuilder) {
+        for (LibraryBuilder part in libraryBuilder.parts) {
           if (isInvalidated(part.uri, part.fileUri)) {
             invalidatedImportUris.add(part.uri);
             builders[part.uri] = part;
           }
         }
-      } else if (library is DillLibraryBuilder) {
-        for (LibraryPart part in library.target.parts) {
-          Uri partUri = library.uri.resolve(part.partUri);
-          Uri fileUri =
-              getPartFileUri(library.library.fileUri, part, uriTranslator);
+      } else if (libraryBuilder is DillLibraryBuilder) {
+        for (LibraryPart part in libraryBuilder.library.parts) {
+          Uri partUri = libraryBuilder.uri.resolve(part.partUri);
+          Uri fileUri = getPartFileUri(
+              libraryBuilder.library.fileUri, part, uriTranslator);
 
           if (isInvalidated(partUri, fileUri)) {
             invalidatedImportUris.add(partUri);
-            builders[partUri] = library;
+            builders[partUri] = libraryBuilder;
           }
         }
       }
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 2b72f56..bf7c912 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -112,7 +112,7 @@
 import 'kernel_builder.dart';
 
 // TODO(ahe): Remove this and ensure all nodes have a location.
-const Token noLocation = null;
+const Null noLocation = null;
 
 // TODO(danrubel): Remove this once control flow and spread collection support
 // has been enabled by default.
@@ -124,7 +124,7 @@
 
   // TODO(ahe): Rename [library] to 'part'.
   @override
-  final SourceLibraryBuilder library;
+  final SourceLibraryBuilder libraryBuilder;
 
   final ModifierBuilder member;
 
@@ -265,7 +265,7 @@
   final List<TypeParameter> extensionTypeParameters;
 
   BodyBuilder(
-      {this.library,
+      {this.libraryBuilder,
       this.member,
       this.enclosingScope,
       this.formalParameterScope,
@@ -280,22 +280,23 @@
       : forest = const Forest(),
         classBuilder =
             declarationBuilder is ClassBuilder ? declarationBuilder : null,
-        enableNative =
-            library.loader.target.backendTarget.enableNative(library.uri),
-        stringExpectedAfterNative =
-            library.loader.target.backendTarget.nativeExtensionExpectsString,
-        ignoreMainInGetMainClosure = library.uri.scheme == 'dart' &&
-            (library.uri.path == "_builtin" || library.uri.path == "ui"),
+        enableNative = libraryBuilder.loader.target.backendTarget
+            .enableNative(libraryBuilder.uri),
+        stringExpectedAfterNative = libraryBuilder
+            .loader.target.backendTarget.nativeExtensionExpectsString,
+        ignoreMainInGetMainClosure = libraryBuilder.uri.scheme == 'dart' &&
+            (libraryBuilder.uri.path == "_builtin" ||
+                libraryBuilder.uri.path == "ui"),
         needsImplicitSuperInitializer = declarationBuilder is ClassBuilder &&
             coreTypes?.objectClass != declarationBuilder.cls,
         typePromoter = typeInferrer?.typePromoter,
-        legacyMode = library.legacyMode,
+        legacyMode = libraryBuilder.legacyMode,
         super(enclosingScope);
 
   BodyBuilder.withParents(FieldBuilder field, SourceLibraryBuilder part,
       DeclarationBuilder declarationBuilder, TypeInferrer typeInferrer)
       : this(
-            library: part,
+            libraryBuilder: part,
             member: field,
             enclosingScope: declarationBuilder?.scope ?? field.library.scope,
             formalParameterScope: null,
@@ -323,7 +324,7 @@
       Scope scope,
       Uri fileUri)
       : this(
-            library: library,
+            libraryBuilder: library,
             member: member,
             enclosingScope: scope,
             formalParameterScope: null,
@@ -481,7 +482,8 @@
     }
     LocatedMessage context = scope.declare(
         variable.name,
-        new VariableBuilder(variable, member ?? classBuilder ?? library, uri),
+        new VariableBuilder(
+            variable, member ?? classBuilder ?? libraryBuilder, uri),
         uri);
     if (context != null) {
       // This case is different from the above error. In this case, the problem
@@ -503,7 +505,7 @@
   void inferAnnotations(List<Expression> annotations) {
     if (annotations != null) {
       typeInferrer?.inferMetadata(this, annotations);
-      library.loader.transformListPostInference(
+      libraryBuilder.loader.transformListPostInference(
           annotations, transformSetLiterals, transformCollections);
     }
   }
@@ -535,14 +537,14 @@
         expression = new UnresolvedNameGenerator(
             this,
             deprecated_extractToken(identifier),
-            new Name(identifier.name, library.nameOrigin));
+            new Name(identifier.name, libraryBuilder.nameOrigin));
       }
       if (name?.isNotEmpty ?? false) {
         Token period = periodBeforeName ?? beginToken.next.next;
         Generator generator = expression;
         expression = generator.buildPropertyAccess(
             new IncompletePropertyAccessGenerator(
-                this, period.next, new Name(name, library.nameOrigin)),
+                this, period.next, new Name(name, libraryBuilder.nameOrigin)),
             period.next.offset,
             false);
       }
@@ -580,17 +582,17 @@
       Token beginToken,
       Token endToken) {
     debugEvent("TopLevelFields");
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportNonNullableModifierError(lateToken);
     }
     push(count);
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     debugEvent("Fields");
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportNonNullableModifierError(lateToken);
     }
     push(count);
@@ -610,30 +612,30 @@
         declaration =
             declarationBuilder.lookupLocalMember(name, required: true);
       } else {
-        declaration = library.lookupLocalMember(name, required: true);
+        declaration = libraryBuilder.lookupLocalMember(name, required: true);
       }
-      FieldBuilder field;
+      FieldBuilder fieldBuilder;
       if (declaration.isField && declaration.next == null) {
-        field = declaration;
+        fieldBuilder = declaration;
       } else {
         continue;
       }
-      fields.add(field);
+      fields.add(fieldBuilder);
       if (initializer != null) {
-        if (field.next != null) {
+        if (fieldBuilder.next != null) {
           // Duplicate definition. The field might not be the correct one,
           // so we skip inference of the initializer.
           // Error reporting and recovery is handled elsewhere.
-        } else if (field.target.initializer != null) {
+        } else if (fieldBuilder.field.initializer != null) {
           // The initializer was already compiled (e.g., if it appear in the
           // outline, like constant field initializers) so we do not need to
           // perform type inference or transformations.
         } else {
-          field.initializer = initializer;
+          fieldBuilder.initializer = initializer;
           typeInferrer?.inferFieldInitializer(
-              this, field.builtType, initializer);
-          library.loader.transformPostInference(
-              field.target, transformSetLiterals, transformCollections);
+              this, fieldBuilder.builtType, initializer);
+          libraryBuilder.loader.transformPostInference(
+              fieldBuilder.field, transformSetLiterals, transformCollections);
         }
       }
     }
@@ -693,8 +695,8 @@
                   formal.name,
                   formal.charOffset,
                   formal.charOffset,
-                  new VariableGet(formal.declaration),
-                  formalType: formal.declaration.type);
+                  new VariableGet(formal.variable),
+                  formalType: formal.variable.type);
             }
             member.addInitializer(initializer, this);
           }
@@ -772,7 +774,7 @@
 
   DartType _computeReturnTypeContext(MemberBuilder member) {
     if (member is ProcedureBuilder) {
-      return member.procedure.function.returnType;
+      return member.actualProcedure.function.returnType;
     } else {
       assert(member is ConstructorBuilder);
       return const DynamicType();
@@ -801,7 +803,7 @@
           realParameter.initializer = initializer..parent = realParameter;
           typeInferrer?.inferParameterInitializer(
               this, initializer, realParameter.type);
-          library.loader.transformPostInference(
+          libraryBuilder.loader.transformPostInference(
               realParameter, transformSetLiterals, transformCollections);
         }
       }
@@ -810,7 +812,7 @@
     typeInferrer?.inferFunctionBody(
         this, _computeReturnTypeContext(member), asyncModifier, body);
     if (body != null) {
-      library.loader.transformPostInference(
+      libraryBuilder.loader.transformPostInference(
           body, transformSetLiterals, transformCollections);
     }
 
@@ -835,14 +837,14 @@
       Message problem;
       switch (asyncModifier) {
         case AsyncMarker.Async:
-          DartType futureBottomType = library.loader.futureOfBottom;
+          DartType futureBottomType = libraryBuilder.loader.futureOfBottom;
           if (!typeEnvironment.isSubtypeOf(futureBottomType, returnType)) {
             problem = fasta.messageIllegalAsyncReturnType;
           }
           break;
 
         case AsyncMarker.AsyncStar:
-          DartType streamBottomType = library.loader.streamOfBottom;
+          DartType streamBottomType = libraryBuilder.loader.streamOfBottom;
           if (returnType is VoidType) {
             problem = fasta.messageIllegalAsyncGeneratorVoidReturnType;
           } else if (!typeEnvironment.isSubtypeOf(
@@ -852,7 +854,7 @@
           break;
 
         case AsyncMarker.SyncStar:
-          DartType iterableBottomType = library.loader.iterableOfBottom;
+          DartType iterableBottomType = libraryBuilder.loader.iterableOfBottom;
           if (returnType is VoidType) {
             problem = fasta.messageIllegalSyncGeneratorVoidReturnType;
           } else if (!typeEnvironment.isSubtypeOf(
@@ -883,7 +885,7 @@
           formals.parameters.single.isOptional) {
         int charOffset = formals?.charOffset ??
             body?.fileOffset ??
-            builder.target.fileOffset;
+            builder.member.fileOffset;
         if (body == null) {
           body = new EmptyStatement()..fileOffset = charOffset;
         }
@@ -958,8 +960,8 @@
     if (member == null) return;
     Library ensureLibraryLoaded = member.enclosingLibrary;
     LibraryBuilder builder =
-        library.loader.builders[ensureLibraryLoaded.importUri] ??
-            library.loader.target.dillTarget.loader
+        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
+            libraryBuilder.loader.target.dillTarget.loader
                 .builders[ensureLibraryLoaded.importUri];
     if (builder is DillLibraryBuilder) {
       builder.ensureLoaded();
@@ -975,8 +977,8 @@
     if (member == null) return true;
     Library ensureLibraryLoaded = member.enclosingLibrary;
     LibraryBuilder builder =
-        library.loader.builders[ensureLibraryLoaded.importUri] ??
-            library.loader.target.dillTarget.loader
+        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
+            libraryBuilder.loader.target.dillTarget.loader
                 .builders[ensureLibraryLoaded.importUri];
     if (builder is DillLibraryBuilder) {
       return builder.isBuiltAndMarked;
@@ -1025,7 +1027,7 @@
       } else if (resolvedTarget is Constructor &&
           resolvedTarget.enclosingClass.isAbstract) {
         replacementNode = evaluateArgumentsBefore(
-            forest.createArguments(invocation.arguments.positional, null,
+            forest.createArguments(noLocation, invocation.arguments.positional,
                 types: invocation.arguments.types,
                 named: invocation.arguments.named),
             buildAbstractClassInstantiationError(
@@ -1046,7 +1048,8 @@
               forest.createNullLiteral(null)
                 ..fileOffset = invocation.fileOffset,
               errorName,
-              forest.createArguments(invocation.arguments.positional, null,
+              forest.createArguments(
+                  noLocation, invocation.arguments.positional,
                   types: invocation.arguments.types,
                   named: invocation.arguments.named),
               initialTarget.fileOffset);
@@ -1064,7 +1067,8 @@
 
           replacementNode = buildStaticInvocation(
               resolvedTarget,
-              forest.createArguments(invocation.arguments.positional, null,
+              forest.createArguments(
+                  noLocation, invocation.arguments.positional,
                   types: invocation.arguments.types,
                   named: invocation.arguments.named),
               constness: invocation.isConst
@@ -1172,8 +1176,8 @@
     List<TypeVariableBuilder> typeParameterBuilders;
     for (TypeParameter typeParameter in parameters.typeParameters) {
       typeParameterBuilders ??= <TypeVariableBuilder>[];
-      typeParameterBuilders
-          .add(new TypeVariableBuilder.fromKernel(typeParameter, library));
+      typeParameterBuilders.add(
+          new TypeVariableBuilder.fromKernel(typeParameter, libraryBuilder));
     }
     enterFunctionTypeScope(typeParameterBuilders);
 
@@ -1185,8 +1189,8 @@
     for (int i = 0; i < parameters.positionalParameters.length; i++) {
       VariableDeclaration formal = parameters.positionalParameters[i];
       formals[i] = new FormalParameterBuilder(
-          null, 0, null, formal.name, library, formal.fileOffset)
-        ..declaration = formal;
+          null, 0, null, formal.name, libraryBuilder, formal.fileOffset)
+        ..variable = formal;
     }
     enterLocalScope(
         null,
@@ -1205,7 +1209,7 @@
               .withLocation(uri, eof.charOffset, eof.length));
     }
 
-    ReturnJudgment fakeReturn = new ReturnJudgment(null, expression);
+    ReturnJudgment fakeReturn = new ReturnJudgment(true, expression);
 
     typeInferrer?.inferFunctionBody(
         this, const DynamicType(), AsyncMarker.Sync, fakeReturn);
@@ -1248,7 +1252,7 @@
     /// Edition](
     /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
     assert(builder == member);
-    Constructor constructor = builder.constructor;
+    Constructor constructor = builder.actualConstructor;
     if (asyncModifier != AsyncMarker.Sync) {
       // TODO(ahe): Change this to a null check.
       int offset = builder.body?.fileOffset ?? builder.charOffset;
@@ -1287,7 +1291,7 @@
       constructor.initializers.add(initializer);
     }
     setParents(constructor.initializers, constructor);
-    library.loader.transformListPostInference(
+    libraryBuilder.loader.transformListPostInference(
         constructor.initializers, transformSetLiterals, transformCollections);
     if (constructor.function.body == null) {
       /// >If a generative constructor c is not a redirecting constructor
@@ -1337,12 +1341,12 @@
           arguments.getRange(0, firstNamedArgumentIndex));
       List<NamedExpression> named = new List<NamedExpression>.from(
           arguments.getRange(firstNamedArgumentIndex, arguments.length));
-      push(forest.createArguments(positional, beginToken, named: named));
+      push(forest.createArguments(beginToken.offset, positional, named: named));
     } else {
       // TODO(kmillikin): Find a way to avoid allocating a second list in the
       // case where there were no named arguments, which is a common one.
       push(forest.createArguments(
-          new List<Expression>.from(arguments), beginToken));
+          beginToken.offset, new List<Expression>.from(arguments)));
     }
   }
 
@@ -1397,7 +1401,7 @@
       assert(typeArguments == null);
     }
     if (receiver is Identifier) {
-      Name name = new Name(receiver.name, library.nameOrigin);
+      Name name = new Name(receiver.name, libraryBuilder.nameOrigin);
       if (arguments == null) {
         push(new IncompletePropertyAccessGenerator(this, beginToken, name));
       } else {
@@ -1432,9 +1436,8 @@
       push(new VariableUseGenerator(this, token, expression.variable));
       expression.extend();
     } else {
-      VariableDeclaration variable = new VariableDeclarationJudgment.forValue(
-          expression, functionNestingLevel)
-        ..fileOffset = expression.fileOffset;
+      VariableDeclaration variable = forest.createVariableDeclarationForValue(
+          expression.fileOffset, expression);
       push(new CascadeJudgment(variable)..fileOffset = expression.fileOffset);
       push(new VariableUseGenerator(this, token, variable));
     }
@@ -1515,7 +1518,7 @@
       }
     } else {
       Expression result = buildMethodInvocation(a, new Name(operator),
-          forest.createArguments(<Expression>[b], noLocation), token.charOffset,
+          forest.createArguments(noLocation, <Expression>[b]), token.charOffset,
           // This *could* be a constant expression, we can't know without
           // evaluating [a] and [b].
           isConstantExpression: !isSuper,
@@ -1594,7 +1597,7 @@
     if (periodIndex != -1) {
       length -= periodIndex + 1;
     }
-    Name kernelName = new Name(name, library.nameOrigin);
+    Name kernelName = new Name(name, libraryBuilder.nameOrigin);
     List<LocatedMessage> context;
     if (candidate != null && candidate.location != null) {
       Uri uri = candidate.location.file;
@@ -1631,7 +1634,7 @@
           wasHandled: true, context: context);
       return forest.createThrow(
           null,
-          library.loader.instantiateNoSuchMethodError(
+          libraryBuilder.loader.instantiateNoSuchMethodError(
               receiver, name, arguments, charOffset,
               isMethod: !isGetter && !isSetter,
               isGetter: isGetter,
@@ -1782,107 +1785,6 @@
         this, token, createVariableGet(variable, charOffset), name);
   }
 
-  @override
-  Expression createExtensionTearOff(
-      Procedure procedure,
-      VariableDeclaration extensionThis,
-      List<TypeParameter> extensionTypeParameters,
-      Token token) {
-    int charOffset = offsetForToken(token);
-
-    FunctionNode function = procedure.function;
-    List<TypeParameter> typeParameters = [];
-    List<DartType> typeArguments = [];
-    int extensionTypeParameterCount = extensionTypeParameters?.length ?? 0;
-    for (int index = 0; index < extensionTypeParameterCount; index++) {
-      typeArguments
-          .add(forest.createTypeParameterType(extensionTypeParameters[index]));
-    }
-    for (int index = extensionTypeParameterCount;
-        index < function.typeParameters.length;
-        index++) {
-      TypeParameter typeParameter = function.typeParameters[index];
-      TypeParameter newTypeParameter =
-          forest.createTypeParameter(typeParameter.name);
-      typeParameters.add(newTypeParameter);
-      typeArguments.add(forest.createTypeParameterType(newTypeParameter));
-    }
-    Substitution substitution =
-        Substitution.fromPairs(function.typeParameters, typeArguments);
-    for (int index = extensionTypeParameterCount;
-        index < function.typeParameters.length;
-        index++) {
-      TypeParameter oldTypeParameter = function.typeParameters[index];
-      TypeParameter newTypeParameter =
-          typeParameters[index - extensionTypeParameterCount];
-      newTypeParameter.bound =
-          substitution.substituteType(oldTypeParameter.bound);
-      newTypeParameter.defaultType = oldTypeParameter.defaultType;
-    }
-
-    DartType returnType = substitution.substituteType(function.returnType);
-
-    List<VariableDeclaration> positionalParameters = [];
-    List<Expression> positionalArguments = [];
-    functionNestingLevel++;
-
-    VariableDeclaration copyParameter(VariableDeclaration parameter,
-        {bool isOptional}) {
-      // TODO(johnniwinther): Handle default values.
-      return forest.createVariableDeclaration(
-          parameter.name, functionNestingLevel,
-          type: substitution.substituteType(parameter.type),
-          initializer: isOptional ? forest.createNullLiteral(token) : null);
-    }
-
-    for (int position = 0;
-        position < function.positionalParameters.length;
-        position++) {
-      VariableDeclaration parameter = function.positionalParameters[position];
-      if (position == 0) {
-        /// Pass `this` as a captured variable.
-        positionalArguments.add(createVariableGet(extensionThis, charOffset));
-      } else {
-        VariableDeclaration newParameter = copyParameter(parameter,
-            isOptional: position >= function.requiredParameterCount);
-        positionalParameters.add(newParameter);
-        positionalArguments.add(createVariableGet(newParameter, charOffset));
-      }
-    }
-    List<VariableDeclaration> namedParameters = [];
-    List<NamedExpression> namedArguments = [];
-    for (VariableDeclaration parameter in function.namedParameters) {
-      VariableDeclaration newParameter =
-          copyParameter(parameter, isOptional: true);
-      namedParameters.add(newParameter);
-      namedArguments.add(forest.createNamedExpression(
-          parameter.name, createVariableGet(newParameter, charOffset)));
-    }
-
-    Statement body = forest.createReturnStatement(
-        null,
-        buildStaticInvocation(
-            procedure,
-            forest.createArguments(positionalArguments, token,
-                types: typeArguments, named: namedArguments),
-            charOffset: charOffset),
-        charOffset);
-
-    FunctionExpression expression = forest.createFunctionExpression(
-        forest.createFunctionNode(body,
-            typeParameters: typeParameters,
-            positionalParameters: positionalParameters,
-            namedParameters: namedParameters,
-            requiredParameterCount:
-                procedure.function.requiredParameterCount - 1,
-            returnType: returnType,
-            asyncMarker: procedure.function.asyncMarker,
-            dartAsyncMarker: procedure.function.dartAsyncMarker),
-        charOffset);
-    functionNestingLevel--;
-    return expression;
-  }
-
   /// Look up [name] in [scope] using [token] as location information (both to
   /// report problems and as the file offset in the generated kernel code).
   /// [isQualified] should be true if [name] is a qualified access (which
@@ -1903,8 +1805,8 @@
         prefix == null &&
         (classBuilder?.isPatch ?? false)) {
       // The scope of a patched method includes the origin class.
-      declaration =
-          classBuilder.origin.findStaticBuilder(name, charOffset, uri, library);
+      declaration = classBuilder.origin
+          .findStaticBuilder(name, charOffset, uri, libraryBuilder);
     }
     if (declaration != null &&
         declaration.isDeclarationInstanceMember &&
@@ -1928,7 +1830,7 @@
             declaration.isDeclarationInstanceMember)) {
       // We either didn't find a declaration or found an instance member from
       // a non-instance context.
-      Name n = new Name(name, library.nameOrigin);
+      Name n = new Name(name, libraryBuilder.nameOrigin);
       if (!isQualified && isDeclarationInstanceContext) {
         assert(declaration == null);
         if (constantContext != ConstantContext.none || member.isField) {
@@ -1987,7 +1889,7 @@
         addProblem(
             fasta.messageNotAConstantExpression, charOffset, token.length);
       }
-      Name n = new Name(name, library.nameOrigin);
+      Name n = new Name(name, libraryBuilder.nameOrigin);
       Member getter;
       Member setter;
       if (declaration is AccessErrorBuilder) {
@@ -2207,8 +2109,8 @@
       push(buildProblemStatement(
           fasta.messageConstructorWithReturnType, beginToken.charOffset));
     } else {
-      push(forest.createReturnStatement(
-          beginToken, expression, offsetForToken(beginToken)));
+      push(forest.createReturnStatement(offsetForToken(beginToken), expression,
+          isArrow: !identical(beginToken.lexeme, "return")));
     }
   }
 
@@ -2292,7 +2194,8 @@
         isLate: isLate)
       ..fileOffset = identifier.charOffset
       ..fileEqualsOffset = offsetForToken(equalsToken);
-    library.checkBoundsInVariableDeclaration(variable, typeEnvironment, uri);
+    libraryBuilder.checkBoundsInVariableDeclaration(
+        variable, typeEnvironment, uri);
     push(variable);
   }
 
@@ -2314,7 +2217,7 @@
     debugEvent("NoFieldInitializer");
     if (constantContext == ConstantContext.inferred) {
       // Creating a null value to prevent the Dart VM from crashing.
-      push(forest.createNullLiteral(token));
+      push(forest.createNullLiteral(offsetForToken(token)));
     } else {
       push(NullValue.FieldInitializer);
     }
@@ -2339,7 +2242,7 @@
   void beginVariablesDeclaration(
       Token token, Token lateToken, Token varFinalOrConst) {
     debugEvent("beginVariablesDeclaration");
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportNonNullableModifierError(lateToken);
     }
     UnresolvedType type = pop();
@@ -2517,17 +2420,6 @@
     Object variableOrExpression = pop();
     exitLocalScope();
 
-    if (!library.loader.target.enableControlFlowCollections) {
-      // TODO(danrubel): Report a more user friendly error message
-      // when an experiment is not enabled
-      handleRecoverableError(
-          fasta.templateUnexpectedToken.withArguments(forToken),
-          forToken,
-          forToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
     if (constantContext != ConstantContext.none) {
       handleRecoverableError(
           fasta.templateCantUseControlFlowOrSpreadAsConstant
@@ -2675,7 +2567,7 @@
         leftBracket,
         expressions,
         rightBracket);
-    library.checkBoundsInListLiteral(node, typeEnvironment, uri);
+    libraryBuilder.checkBoundsInListLiteral(node, typeEnvironment, uri);
     push(node);
   }
 
@@ -2684,7 +2576,7 @@
     DartType typeArgument;
     if (typeArguments != null) {
       typeArgument = buildDartType(typeArguments.single);
-      if (!library.loader.target.legacyMode) {
+      if (!libraryBuilder.loader.target.legacyMode) {
         typeArgument = instantiateToBounds(typeArgument, coreTypes.objectClass);
       }
     } else {
@@ -2714,7 +2606,7 @@
         leftBrace,
         expressions,
         leftBrace.endGroup);
-    library.checkBoundsInSetLiteral(node, typeEnvironment, uri);
+    libraryBuilder.checkBoundsInSetLiteral(node, typeEnvironment, uri);
     push(node);
   }
 
@@ -2800,7 +2692,7 @@
   @override
   void handleLiteralNull(Token token) {
     debugEvent("LiteralNull");
-    push(forest.createNullLiteral(token));
+    push(forest.createNullLiteral(offsetForToken(token)));
   }
 
   void buildLiteralMap(List<UnresolvedType> typeArguments, Token constKeyword,
@@ -2834,7 +2726,7 @@
         leftBrace,
         entries,
         leftBrace.endGroup);
-    library.checkBoundsInMapLiteral(node, typeEnvironment, uri);
+    libraryBuilder.checkBoundsInMapLiteral(node, typeEnvironment, uri);
     push(node);
   }
 
@@ -2885,7 +2777,7 @@
 
   @override
   void handleNonNullAssertExpression(Token bang) {
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportNonNullAssertExpressionNotEnabled(bang);
     }
   }
@@ -2894,9 +2786,10 @@
   void handleType(Token beginToken, Token questionMark) {
     // TODO(ahe): The scope is wrong for return types of generic functions.
     debugEvent("Type");
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportErrorIfNullableType(questionMark);
     }
+    bool isMarkedAsNullable = questionMark != null;
     List<UnresolvedType> arguments = pop();
     Object name = pop();
     if (name is QualifiedName) {
@@ -2910,10 +2803,13 @@
         String displayName = debugName(name, suffix.lexeme);
         int offset = offsetForToken(beginToken);
         Message message = fasta.templateNotAType.withArguments(displayName);
-        library.addProblem(
+        libraryBuilder.addProblem(
             message, offset, lengthOfSpan(beginToken, suffix), uri);
         push(new UnresolvedType(
-            new NamedTypeBuilder(name, null)
+            new NamedTypeBuilder(
+                name,
+                libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable),
+                null)
               ..bind(new InvalidTypeBuilder(
                   name,
                   message.withLocation(
@@ -2925,15 +2821,18 @@
     }
     TypeBuilder result;
     if (name is Generator) {
-      result = name.buildTypeWithResolvedArguments(arguments);
+      result = name.buildTypeWithResolvedArguments(
+          libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable),
+          arguments);
       if (result == null) {
         unhandled("null", "result", beginToken.charOffset, uri);
       }
     } else if (name is ProblemBuilder) {
       // TODO(ahe): Arguments could be passed here.
-      library.addProblem(
+      libraryBuilder.addProblem(
           name.message, name.charOffset, name.name.length, name.fileUri);
-      result = new NamedTypeBuilder(name.name, null)
+      result = new NamedTypeBuilder(name.name,
+          libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable), null)
         ..bind(new InvalidTypeBuilder(
             name.name,
             name.message.withLocation(
@@ -2971,7 +2870,7 @@
   @override
   void endFunctionType(Token functionToken, Token questionMark) {
     debugEvent("FunctionType");
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportErrorIfNullableType(questionMark);
     }
     FormalParameters formals = pop();
@@ -2986,9 +2885,10 @@
   void handleVoidKeyword(Token token) {
     debugEvent("VoidKeyword");
     int offset = offsetForToken(token);
+    // "void" is always nullable.
     push(new UnresolvedType(
-        new NamedTypeBuilder("void", null)
-          ..bind(new VoidTypeBuilder(const VoidType(), library, offset)),
+        new NamedTypeBuilder("void", const NullabilityBuilder.nullable(), null)
+          ..bind(new VoidTypeBuilder(const VoidType(), libraryBuilder, offset)),
         offset,
         uri));
   }
@@ -2997,18 +2897,12 @@
   void handleAsOperator(Token operator) {
     debugEvent("AsOperator");
     DartType type = buildDartType(pop());
-    library.checkBoundsInType(type, typeEnvironment, uri, operator.charOffset);
+    libraryBuilder.checkBoundsInType(
+        type, typeEnvironment, uri, operator.charOffset);
     Expression expression = popForValue();
-    if (!library.loader.target.enableConstantUpdate2018 &&
-        constantContext != ConstantContext.none) {
-      push(desugarSyntheticExpression(buildProblem(
-          fasta.templateNotConstantExpression.withArguments('As expression'),
-          operator.charOffset,
-          operator.length)));
-    } else {
-      Expression node = forest.createAsExpression(expression, type, operator);
-      push(node);
-    }
+    Expression asExpression =
+        forest.createAsExpression(expression, type, operator);
+    push(asExpression);
   }
 
   @override
@@ -3019,21 +2913,13 @@
     bool isInverted = not != null;
     Expression isExpression =
         forest.createIsExpression(operand, isOperator, not, type);
-    library.checkBoundsInType(
+    libraryBuilder.checkBoundsInType(
         type, typeEnvironment, uri, isOperator.charOffset);
     if (operand is VariableGet) {
       typePromoter?.handleIsCheck(isExpression, isInverted, operand.variable,
           type, functionNestingLevel);
     }
-    if (!library.loader.target.enableConstantUpdate2018 &&
-        constantContext != ConstantContext.none) {
-      push(desugarSyntheticExpression(buildProblem(
-          fasta.templateNotConstantExpression.withArguments('Is expression'),
-          isOperator.charOffset,
-          isOperator.length)));
-    } else {
-      push(isExpression);
-    }
+    push(isExpression);
   }
 
   @override
@@ -3081,7 +2967,7 @@
   void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
       Token covariantToken, Token varFinalOrConst) {
     // TODO(danrubel): handle required token
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportNonNullableModifierError(requiredToken);
     }
     push((covariantToken != null ? covariantMask : 0) |
@@ -3139,10 +3025,10 @@
       }
     } else {
       parameter = new FormalParameterBuilder(null, modifiers, type?.builder,
-          name?.name, library, offsetForToken(nameToken));
+          name?.name, libraryBuilder, offsetForToken(nameToken));
     }
     VariableDeclaration variable =
-        parameter.build(library, functionNestingLevel);
+        parameter.build(libraryBuilder, functionNestingLevel);
     Expression initializer = name?.initializer;
     if (initializer != null) {
       if (member is RedirectingFactoryBuilder) {
@@ -3208,7 +3094,7 @@
     FormalParameters formals = pop();
     UnresolvedType returnType = pop();
     List<TypeVariableBuilder> typeVariables = pop();
-    if (!library.loader.target.enableNonNullable) {
+    if (!libraryBuilder.loader.target.enableNonNullable) {
       reportErrorIfNullableType(question);
     }
     UnresolvedType type = formals.toFunctionType(returnType, typeVariables);
@@ -3281,7 +3167,7 @@
       enterLocalScope(
           null,
           formals.computeFormalParameterScope(
-              scope, member ?? classBuilder ?? library, this));
+              scope, member ?? classBuilder ?? libraryBuilder, this));
     }
   }
 
@@ -3317,10 +3203,11 @@
       int parameterCount = catchParameters.parameters.length;
       if (parameterCount > 0) {
         exception = catchParameters.parameters[0];
-        exception.build(library, functionNestingLevel).type = exceptionType;
+        exception.build(libraryBuilder, functionNestingLevel).type =
+            exceptionType;
         if (parameterCount > 1) {
           stackTrace = catchParameters.parameters[1];
-          stackTrace.build(library, functionNestingLevel).type =
+          stackTrace.build(libraryBuilder, functionNestingLevel).type =
               coreTypes.stackTraceClass.rawType;
         }
       }
@@ -3611,7 +3498,8 @@
       ConstructorInvocation node =
           new ConstructorInvocation(target, arguments, isConst: isConst)
             ..fileOffset = charOffset;
-      library.checkBoundsInConstructorInvocation(node, typeEnvironment, uri);
+      libraryBuilder.checkBoundsInConstructorInvocation(
+          node, typeEnvironment, uri);
       return node;
     } else {
       Procedure procedure = target;
@@ -3627,22 +3515,49 @@
               arguments,
               charOffset);
         }
-        StaticInvocation node = FactoryConstructorInvocationJudgment(
+        StaticInvocation node = new FactoryConstructorInvocationJudgment(
             target, arguments,
             isConst: isConst)
           ..fileOffset = charOffset;
-        library.checkBoundsInFactoryInvocation(node, typeEnvironment, uri);
+        libraryBuilder.checkBoundsInFactoryInvocation(
+            node, typeEnvironment, uri);
         return node;
       } else {
         StaticInvocation node =
             new StaticInvocation(target, arguments, isConst: isConst)
               ..fileOffset = charOffset;
-        library.checkBoundsInStaticInvocation(node, typeEnvironment, uri);
+        libraryBuilder.checkBoundsInStaticInvocation(
+            node, typeEnvironment, uri);
         return node;
       }
     }
   }
 
+  Expression buildExtensionMethodInvocation(
+      int fileOffset, Procedure target, Arguments arguments) {
+    // TODO(johnniwinther): Check type argument count.
+    List<TypeParameter> typeParameters = target.function.typeParameters;
+    LocatedMessage argMessage = checkArgumentsForFunction(
+        target.function, arguments, fileOffset, typeParameters);
+    if (argMessage != null) {
+      return wrapSyntheticExpression(
+          throwNoSuchMethodError(
+              forest.createNullLiteral(null)..fileOffset = fileOffset,
+              target.name.name,
+              arguments,
+              fileOffset,
+              candidate: target,
+              message: argMessage),
+          fileOffset);
+    }
+
+    StaticInvocation node = new StaticInvocation(target, arguments)
+      ..fileOffset = fileOffset;
+    // TODO(johnniwinther): Check type argument bounds.
+    //libraryBuilder.checkBoundsInStaticInvocation(node, typeEnvironment, uri);
+    return node;
+  }
+
   @override
   LocatedMessage checkArgumentsForFunction(FunctionNode function,
       Arguments arguments, int offset, List<TypeParameter> typeParameters) {
@@ -3870,7 +3785,8 @@
         return buildProblem(fasta.messageEnumInstantiation,
             nameToken.charOffset, nameToken.length);
       }
-      Builder b = type.findConstructorOrFactory(name, charOffset, uri, library);
+      Builder b =
+          type.findConstructorOrFactory(name, charOffset, uri, libraryBuilder);
       Member target = b?.target;
       if (b == null) {
         // Not found. Reported below.
@@ -3904,7 +3820,7 @@
               target.function.typeParameters.length !=
                   forest.argumentsTypeArguments(arguments).length) {
             arguments = forest.createArguments(
-                forest.argumentsPositional(arguments), null,
+                noLocation, forest.argumentsPositional(arguments),
                 named: forest.argumentsNamed(arguments),
                 types: new List<DartType>.filled(
                     target.function.typeParameters.length, const DynamicType(),
@@ -3987,27 +3903,6 @@
     Token ifToken = pop();
     typePromoter?.enterElse();
     typePromoter?.exitConditional();
-    if (!library.loader.target.enableControlFlowCollections) {
-      // TODO(danrubel): Report a more user friendly error message
-      // when an experiment is not enabled
-      handleRecoverableError(
-          fasta.templateUnexpectedToken.withArguments(ifToken),
-          ifToken,
-          ifToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
-    if (constantContext != ConstantContext.none &&
-        !library.loader.target.enableConstantUpdate2018) {
-      handleRecoverableError(
-          fasta.templateCantUseControlFlowOrSpreadAsConstant
-              .withArguments(ifToken),
-          ifToken,
-          ifToken);
-      push(invalidCollectionElement);
-      return;
-    }
 
     transformCollections = true;
     if (entry is MapEntry) {
@@ -4026,27 +3921,6 @@
     Object condition = pop(); // parenthesized expression
     Token ifToken = pop();
     typePromoter?.exitConditional();
-    if (!library.loader.target.enableControlFlowCollections) {
-      // TODO(danrubel): Report a more user friendly error message
-      // when an experiment is not enabled
-      handleRecoverableError(
-          fasta.templateUnexpectedToken.withArguments(ifToken),
-          ifToken,
-          ifToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
-    if (constantContext != ConstantContext.none &&
-        !library.loader.target.enableConstantUpdate2018) {
-      handleRecoverableError(
-          fasta.templateCantUseControlFlowOrSpreadAsConstant
-              .withArguments(ifToken),
-          ifToken,
-          ifToken);
-      push(invalidCollectionElement);
-      return;
-    }
 
     transformCollections = true;
     if (thenEntry is MapEntry) {
@@ -4100,26 +3974,6 @@
   void handleSpreadExpression(Token spreadToken) {
     debugEvent("SpreadExpression");
     Object expression = pop();
-    if (!library.loader.target.enableSpreadCollections) {
-      handleRecoverableError(
-          fasta.templateUnexpectedToken.withArguments(spreadToken),
-          spreadToken,
-          spreadToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
-    if (constantContext != ConstantContext.none &&
-        !library.loader.target.enableConstantUpdate2018) {
-      handleRecoverableError(
-          fasta.templateCantUseControlFlowOrSpreadAsConstant
-              .withArguments(spreadToken),
-          spreadToken,
-          spreadToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
     transformCollections = true;
     push(forest.createSpreadElement(toValue(expression), spreadToken));
   }
@@ -4261,8 +4115,8 @@
     if (!isFunctionExpression) {
       annotations = pop(); // Metadata.
     }
-    FunctionNode function = formals.buildFunctionNode(library, returnType,
-        typeParameters, asyncModifier, body, token.charOffset);
+    FunctionNode function = formals.buildFunctionNode(libraryBuilder,
+        returnType, typeParameters, asyncModifier, body, token.charOffset);
 
     if (declaration is FunctionDeclaration) {
       VariableDeclaration variable = declaration.variable;
@@ -4343,11 +4197,11 @@
     FormalParameters formals = pop();
     exitFunction();
     List<TypeVariableBuilder> typeParameters = pop();
-    FunctionNode function = formals.buildFunctionNode(
-        library, null, typeParameters, asyncModifier, body, token.charOffset)
+    FunctionNode function = formals.buildFunctionNode(libraryBuilder, null,
+        typeParameters, asyncModifier, body, token.charOffset)
       ..fileOffset = beginToken.charOffset;
 
-    if (library.legacyMode && asyncModifier != AsyncMarker.Sync) {
+    if (libraryBuilder.legacyMode && asyncModifier != AsyncMarker.Sync) {
       DartType returnType;
       switch (asyncModifier) {
         case AsyncMarker.Async:
@@ -4427,17 +4281,6 @@
     Object lvalue = pop(); // lvalue
     exitLocalScope();
 
-    if (!library.loader.target.enableControlFlowCollections) {
-      // TODO(danrubel): Report a more user friendly error message
-      // when an experiment is not enabled
-      handleRecoverableError(
-          fasta.templateUnexpectedToken.withArguments(forToken),
-          forToken,
-          forToken);
-      push(invalidCollectionElement);
-      return;
-    }
-
     if (constantContext != ConstantContext.none) {
       handleRecoverableError(
           fasta.templateCantUseControlFlowOrSpreadAsConstant
@@ -4465,7 +4308,7 @@
 
   VariableDeclaration buildForInVariable(Object lvalue) {
     if (lvalue is VariableDeclaration) return lvalue;
-    return new VariableDeclarationJudgment.forValue(null, functionNestingLevel);
+    return forest.createVariableDeclarationForValue(noLocation, null);
   }
 
   Expression checkForInVariable(
@@ -4987,7 +4830,7 @@
     Identifier name = pop();
     List<Expression> annotations = pop();
     TypeVariableBuilder variable =
-        new TypeVariableBuilder(name.name, library, name.charOffset);
+        new TypeVariableBuilder(name.name, libraryBuilder, name.charOffset);
     if (annotations != null) {
       inferAnnotations(annotations);
       for (Expression annotation in annotations) {
@@ -5027,25 +4870,28 @@
     if (!legacyMode) {
       List<TypeBuilder> calculatedBounds = calculateBounds(
           typeVariables,
-          library.loader.target.dynamicType,
-          library.loader.target.bottomType,
-          library.loader.target.objectClassBuilder);
+          libraryBuilder.loader.target.dynamicType,
+          libraryBuilder.loader.target.bottomType,
+          libraryBuilder.loader.target.objectClassBuilder);
       for (int i = 0; i < typeVariables.length; ++i) {
         typeVariables[i].defaultType = calculatedBounds[i];
-        typeVariables[i].defaultType.resolveIn(scope,
-            typeVariables[i].charOffset, typeVariables[i].fileUri, library);
+        typeVariables[i].defaultType.resolveIn(
+            scope,
+            typeVariables[i].charOffset,
+            typeVariables[i].fileUri,
+            libraryBuilder);
         typeVariables[i].finish(
-            library,
-            library.loader.target.objectClassBuilder,
-            library.loader.target.dynamicType);
+            libraryBuilder,
+            libraryBuilder.loader.target.objectClassBuilder,
+            libraryBuilder.loader.target.dynamicType);
       }
     } else {
       for (int i = 0; i < typeVariables.length; ++i) {
-        typeVariables[i].defaultType = library.loader.target.dynamicType;
+        typeVariables[i].defaultType = libraryBuilder.loader.target.dynamicType;
         typeVariables[i].finish(
-            library,
-            library.loader.target.objectClassBuilder,
-            library.loader.target.dynamicType);
+            libraryBuilder,
+            libraryBuilder.loader.target.objectClassBuilder,
+            libraryBuilder.loader.target.dynamicType);
       }
     }
   }
@@ -5065,7 +4911,7 @@
         growable: true);
     int i = 0;
     for (TypeVariableBuilder builder in typeVariableBuilders) {
-      typeParameters[i++] = builder.target;
+      typeParameters[i++] = builder.parameter;
     }
     return typeParameters;
   }
@@ -5084,7 +4930,7 @@
       addProblem(message, charOffset, length,
           wasHandled: true, context: context);
     }
-    String text = library.loader.target.context
+    String text = libraryBuilder.loader.target.context
         .format(message.withLocation(uri, charOffset, length), Severity.error);
     return wrapSyntheticExpression(
         new InvalidExpression(text)..fileOffset = charOffset, charOffset);
@@ -5137,13 +4983,14 @@
     return forest.createThrow(
         null,
         buildStaticInvocation(
-            library.loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
-            forest.createArguments(<Expression>[
+            libraryBuilder
+                .loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
+            forest.createArguments(noLocation, <Expression>[
               forest.createStringLiteral("${location?.file ?? uri}", null)
                 ..fileOffset = charOffset,
               forest.createIntLiteral(location?.line ?? 0, null)
                 ..fileOffset = charOffset,
-            ], noLocation),
+            ]),
             charOffset: charOffset))
       ..fileOffset = charOffset;
   }
@@ -5153,13 +5000,13 @@
       [int charOffset = -1]) {
     addProblemErrorIfConst(message, charOffset, className.length);
     // TODO(ahe): The following doesn't make sense to Analyzer AST.
-    Builder constructor = library.loader.getAbstractClassInstantiationError();
+    Builder constructor =
+        libraryBuilder.loader.getAbstractClassInstantiationError();
     Expression invocation = buildStaticInvocation(
         constructor.target,
-        forest.createArguments(<Expression>[
+        forest.createArguments(charOffset, <Expression>[
           forest.createStringLiteral(className, null)..fileOffset = charOffset
-        ], noLocation)
-          ..fileOffset = charOffset,
+        ]),
         charOffset: charOffset);
     if (invocation is shadow.SyntheticExpressionJudgment) {
       invocation = desugarSyntheticExpression(invocation);
@@ -5257,14 +5104,13 @@
                   .withLocation(uri, builder.charOffset, name.length)
             ]);
         Builder constructor =
-            library.loader.getDuplicatedFieldInitializerError();
+            libraryBuilder.loader.getDuplicatedFieldInitializerError();
         Expression invocation = buildStaticInvocation(
             constructor.target,
-            forest.createArguments(<Expression>[
+            forest.createArguments(assignmentOffset, <Expression>[
               forest.createStringLiteral(name, null)
                 ..fileOffset = assignmentOffset
-            ], noLocation)
-              ..fileOffset = assignmentOffset,
+            ]),
             charOffset: assignmentOffset);
         if (invocation is shadow.SyntheticExpressionJudgment) {
           invocation = desugarSyntheticExpression(invocation);
@@ -5280,7 +5126,7 @@
         if (!legacyMode &&
             formalType != null &&
             !typeEnvironment.isSubtypeOf(formalType, builder.field.type)) {
-          library.addProblem(
+          libraryBuilder.addProblem(
               fasta.templateInitializingFormalTypeMismatch
                   .withArguments(name, formalType, builder.field.type),
               assignmentOffset,
@@ -5375,7 +5221,8 @@
       UnresolvedType unresolved, bool nonInstanceAccessIsError) {
     TypeBuilder builder = unresolved.builder;
     if (builder is NamedTypeBuilder && builder.declaration.isTypeVariable) {
-      TypeParameter typeParameter = builder.declaration.target;
+      TypeVariableBuilder typeParameterBuilder = builder.declaration;
+      TypeParameter typeParameter = typeParameterBuilder.parameter;
       LocatedMessage message;
       if (!isDeclarationInstanceContext && typeParameter.parent is Class) {
         message = fasta.messageTypeVariableInStaticContext.withLocation(
@@ -5392,7 +5239,8 @@
       }
       addProblem(message.messageObject, message.charOffset, message.length);
       return new UnresolvedType(
-          new NamedTypeBuilder(typeParameter.name, null)
+          new NamedTypeBuilder(
+              typeParameter.name, builder.nullabilityBuilder, null)
             ..bind(new InvalidTypeBuilder(typeParameter.name, message)),
           unresolved.charOffset,
           unresolved.fileUri);
@@ -5494,7 +5342,7 @@
       {bool wasHandled: false,
       List<LocatedMessage> context,
       Severity severity}) {
-    library.addProblem(message, charOffset, length, uri,
+    libraryBuilder.addProblem(message, charOffset, length, uri,
         wasHandled: wasHandled, context: context, severity: severity);
   }
 
@@ -5554,7 +5402,7 @@
   }
 
   bool isErroneousNode(TreeNode node) {
-    return library.loader.handledErrors.isNotEmpty &&
+    return libraryBuilder.loader.handledErrors.isNotEmpty &&
         forest.isErroneousNode(node);
   }
 
@@ -5564,7 +5412,7 @@
     if (unresolvedType == null) return null;
     return validateTypeUse(unresolvedType, nonInstanceAccessIsError)
         .builder
-        ?.build(library);
+        ?.build(libraryBuilder);
   }
 
   @override
@@ -5862,7 +5710,11 @@
         local[parameter.name] = parameter;
       }
     }
-    return new Scope(local, null, parent, "formals", isModifiable: false);
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "formals",
+        isModifiable: false);
   }
 
   String toString() {
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 131372b..075dc56 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
@@ -85,6 +85,7 @@
         ProcedureBuilder,
         LibraryBuilder,
         MemberBuilder,
+        NullabilityBuilder,
         TypeBuilder,
         TypeVariableBuilder;
 
@@ -106,8 +107,8 @@
   return member is Procedure ? member.kind : null;
 }
 
-bool isNameVisibleIn(Name name, LibraryBuilder library) {
-  return !name.isPrivate || name.library == library.target;
+bool isNameVisibleIn(Name name, LibraryBuilder libraryBuilder) {
+  return !name.isPrivate || name.library == libraryBuilder.library;
 }
 
 /// Returns true if [a] is a class member conflict with [b].  [a] is assumed to
@@ -196,19 +197,19 @@
 class ClassHierarchyBuilder {
   final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
 
-  final ClassBuilder objectClass;
+  final ClassBuilder objectClassBuilder;
 
   final Loader loader;
 
-  final Class objectKernelClass;
+  final Class objectClass;
 
-  final Class futureKernelClass;
+  final Class futureClass;
 
-  final Class futureOrKernelClass;
+  final Class futureOrClass;
 
-  final Class functionKernelClass;
+  final Class functionClass;
 
-  final Class nullKernelClass;
+  final Class nullClass;
 
   final List<DelayedOverrideCheck> overrideChecks = <DelayedOverrideCheck>[];
 
@@ -219,18 +220,18 @@
 
   Types types;
 
-  ClassHierarchyBuilder(this.objectClass, this.loader, this.coreTypes)
-      : objectKernelClass = objectClass.target,
-        futureKernelClass = coreTypes.futureClass,
-        futureOrKernelClass = coreTypes.futureOrClass,
-        functionKernelClass = coreTypes.functionClass,
-        nullKernelClass = coreTypes.nullClass {
+  ClassHierarchyBuilder(this.objectClassBuilder, this.loader, this.coreTypes)
+      : objectClass = objectClassBuilder.cls,
+        futureClass = coreTypes.futureClass,
+        futureOrClass = coreTypes.futureOrClass,
+        functionClass = coreTypes.functionClass,
+        nullClass = coreTypes.nullClass {
     types = new Types(this);
   }
 
-  ClassHierarchyNode getNodeFromClass(ClassBuilder cls) {
-    return nodes[cls.target] ??=
-        new ClassHierarchyNodeBuilder(this, cls).build();
+  ClassHierarchyNode getNodeFromClass(ClassBuilder classBuilder) {
+    return nodes[classBuilder.cls] ??=
+        new ClassHierarchyNodeBuilder(this, classBuilder).build();
   }
 
   ClassHierarchyNode getNodeFromType(TypeBuilder type) {
@@ -246,12 +247,14 @@
   TypeBuilder asSupertypeOf(Class cls, Class supertype) {
     ClassHierarchyNode clsNode = getNodeFromKernelClass(cls);
     if (cls == supertype) {
-      return new NamedTypeBuilder(clsNode.cls.name, null)..bind(clsNode.cls);
+      return new NamedTypeBuilder(clsNode.classBuilder.name,
+          const NullabilityBuilder.pendingImplementation(), null)
+        ..bind(clsNode.classBuilder);
     }
     ClassHierarchyNode supertypeNode = getNodeFromKernelClass(supertype);
     List<TypeBuilder> supertypes = clsNode.superclasses;
     int depth = supertypeNode.depth;
-    Builder supertypeDeclaration = supertypeNode.cls;
+    Builder supertypeDeclaration = supertypeNode.classBuilder;
     if (depth < supertypes.length) {
       TypeBuilder asSupertypeOf = supertypes[depth];
       if (asSupertypeOf.declaration == supertypeDeclaration) {
@@ -270,7 +273,7 @@
       InterfaceType type, Class superclass) {
     Class kernelClass = type.classNode;
     if (kernelClass == superclass) return type;
-    if (kernelClass == nullKernelClass) {
+    if (kernelClass == nullClass) {
       if (superclass.typeParameters.isEmpty) {
         return superclass.rawType;
       } else {
@@ -279,7 +282,7 @@
         return new InterfaceType(
             superclass,
             new List<DartType>.filled(
-                superclass.typeParameters.length, nullKernelClass.rawType));
+                superclass.typeParameters.length, nullClass.rawType));
       }
     }
     NamedTypeBuilder supertype = asSupertypeOf(kernelClass, superclass);
@@ -304,28 +307,30 @@
       ClassHierarchyNode node = nodes2[i];
       if (node == null) continue;
       if (nodes1.contains(node)) {
-        DartType candidate1 = getKernelTypeAsInstanceOf(type1, node.cls.target);
-        DartType candidate2 = getKernelTypeAsInstanceOf(type2, node.cls.target);
+        DartType candidate1 =
+            getKernelTypeAsInstanceOf(type1, node.classBuilder.cls);
+        DartType candidate2 =
+            getKernelTypeAsInstanceOf(type2, node.classBuilder.cls);
         if (candidate1 == candidate2) {
           common.add(node);
         }
       }
     }
 
-    if (common.length == 1) return objectKernelClass.rawType;
+    if (common.length == 1) return objectClass.rawType;
     common.sort(ClassHierarchyNode.compareMaxInheritancePath);
 
     for (int i = 0; i < common.length - 1; i++) {
       ClassHierarchyNode node = common[i];
       if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
-        return getKernelTypeAsInstanceOf(type1, node.cls.target);
+        return getKernelTypeAsInstanceOf(type1, node.classBuilder.cls);
       } else {
         do {
           i++;
         } while (node.maxInheritancePath == common[i + 1].maxInheritancePath);
       }
     }
-    return objectKernelClass.rawType;
+    return objectClass.rawType;
   }
 
   Member getInterfaceMemberKernel(Class cls, Name name, bool isSetter) {
@@ -365,10 +370,10 @@
     ClassHierarchyBuilder hierarchy =
         new ClassHierarchyBuilder(objectClass, loader, coreTypes);
     for (int i = 0; i < classes.length; i++) {
-      ClassBuilder cls = classes[i];
-      if (!cls.isPatch) {
-        hierarchy.nodes[cls.target] =
-            new ClassHierarchyNodeBuilder(hierarchy, cls).build();
+      ClassBuilder classBuilder = classes[i];
+      if (!classBuilder.isPatch) {
+        hierarchy.nodes[classBuilder.cls] =
+            new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
       } else {
         // TODO(ahe): Merge the injected members of patch into the hierarchy
         // node of `cls.origin`.
@@ -381,15 +386,15 @@
 class ClassHierarchyNodeBuilder {
   final ClassHierarchyBuilder hierarchy;
 
-  final ClassBuilder cls;
+  final ClassBuilder classBuilder;
 
   bool hasNoSuchMethod = false;
 
   List<Builder> abstractMembers = null;
 
-  ClassHierarchyNodeBuilder(this.hierarchy, this.cls);
+  ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
 
-  ClassBuilder get objectClass => hierarchy.objectClass;
+  ClassBuilder get objectClass => hierarchy.objectClassBuilder;
 
   final Map<Class, Substitution> substitutions = <Class, Substitution>{};
 
@@ -422,7 +427,8 @@
       case MergeKind.superclassSetters:
         // [a] is a method declared in [cls]. This means it defines the
         // interface of this class regardless if its abstract.
-        debug?.log("superclass: checkValidOverride(${cls.fullNameForErrors}, "
+        debug?.log("superclass: checkValidOverride("
+            "${classBuilder.fullNameForErrors}, "
             "${fullName(a)}, ${fullName(b)})");
         checkValidOverride(
             a, AbstractMemberOverridingImplementation.selectAbstract(b));
@@ -431,26 +437,27 @@
           if (isAbstract(b)) {
             recordAbstractMember(a);
           } else {
-            if (!cls.isAbstract) {
+            if (!classBuilder.isAbstract) {
               // The interface of this class is [a]. But the implementation is
               // [b]. So [b] must implement [a], unless [cls] is abstract.
               checkValidOverride(b, a);
             }
             result = new AbstractMemberOverridingImplementation(
-                cls,
+                classBuilder,
                 a,
                 AbstractMemberOverridingImplementation.selectConcrete(b),
                 mergeKind == MergeKind.superclassSetters,
-                cls.library.loader == hierarchy.loader);
+                classBuilder.library.loader == hierarchy.loader);
             hierarchy.delayedMemberChecks.add(result);
           }
-        } else if (cls.isMixinApplication && a.parent != cls) {
+        } else if (classBuilder.isMixinApplication &&
+            a.parent != classBuilder) {
           result = InheritedImplementationInterfaceConflict.combined(
-              cls,
+              classBuilder,
               a,
               b,
               mergeKind == MergeKind.superclassSetters,
-              cls.library.loader == hierarchy.loader,
+              classBuilder.library.loader == hierarchy.loader,
               isInheritableConflict: false);
           if (result is DelayedMember) {
             hierarchy.delayedMemberChecks.add(result);
@@ -466,32 +473,34 @@
 
       case MergeKind.membersWithSetters:
       case MergeKind.settersWithMembers:
-        if (a.parent == cls && b.parent != cls) {
+        if (a.parent == classBuilder && b.parent != classBuilder) {
           if (a is FieldBuilder) {
             if (a.isFinal && b.isSetter) {
-              hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+              hierarchy.overrideChecks
+                  .add(new DelayedOverrideCheck(classBuilder, a, b));
             } else {
               if (!inferFieldTypes(a, b)) {
                 hierarchy.overrideChecks
-                    .add(new DelayedOverrideCheck(cls, a, b));
+                    .add(new DelayedOverrideCheck(classBuilder, a, b));
               }
             }
           } else if (a is ProcedureBuilder) {
             if (!inferMethodTypes(a, b)) {
-              hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+              hierarchy.overrideChecks
+                  .add(new DelayedOverrideCheck(classBuilder, a, b));
             }
           }
         }
         break;
 
       case MergeKind.interfacesMembers:
-        result = InterfaceConflict.combined(
-            cls, a, b, false, cls.library.loader == hierarchy.loader);
+        result = InterfaceConflict.combined(classBuilder, a, b, false,
+            classBuilder.library.loader == hierarchy.loader);
         break;
 
       case MergeKind.interfacesSetters:
-        result = InterfaceConflict.combined(
-            cls, a, b, true, cls.library.loader == hierarchy.loader);
+        result = InterfaceConflict.combined(classBuilder, a, b, true,
+            classBuilder.library.loader == hierarchy.loader);
         break;
 
       case MergeKind.supertypesMembers:
@@ -502,8 +511,9 @@
         b = AbstractMemberOverridingImplementation.selectAbstract(b);
 
         // If [a] is declared in this class, it defines the interface.
-        if (a.parent == cls) {
-          debug?.log("supertypes: checkValidOverride(${cls.fullNameForErrors}, "
+        if (a.parent == classBuilder) {
+          debug?.log("supertypes: checkValidOverride("
+              "${classBuilder.fullNameForErrors}, "
               "${fullName(a)}, ${fullName(b)})");
           checkValidOverride(a, b);
           if (a is DelayedMember && !a.isInheritableConflict) {
@@ -516,18 +526,18 @@
         } else {
           if (isAbstract(a)) {
             result = InterfaceConflict.combined(
-                cls,
+                classBuilder,
                 a,
                 b,
                 mergeKind == MergeKind.supertypesSetters,
-                cls.library.loader == hierarchy.loader);
+                classBuilder.library.loader == hierarchy.loader);
           } else {
             result = InheritedImplementationInterfaceConflict.combined(
-                cls,
+                classBuilder,
                 a,
                 b,
                 mergeKind == MergeKind.supertypesSetters,
-                cls.library.loader == hierarchy.loader);
+                classBuilder.library.loader == hierarchy.loader);
           }
           debug?.log("supertypes: ${result}");
           if (result is DelayedMember) {
@@ -583,25 +593,29 @@
       return inferSetterType(a, b);
     }
     bool hadTypesInferred = a.hadTypesInferred;
-    ClassBuilder aCls = a.parent;
+    ClassBuilder aClassBuilder = a.parent;
     Substitution aSubstitution;
-    if (cls != aCls) {
-      assert(substitutions.containsKey(aCls.target),
-          "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
-      aSubstitution = substitutions[aCls.target];
-      debug?.log("${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} "
-          "$aSubstitution");
+    if (classBuilder != aClassBuilder) {
+      assert(
+          substitutions.containsKey(aClassBuilder.cls),
+          "${classBuilder.fullNameForErrors} "
+          "${aClassBuilder.fullNameForErrors}");
+      aSubstitution = substitutions[aClassBuilder.cls];
+      debug?.log("${classBuilder.fullNameForErrors} -> "
+          "${aClassBuilder.fullNameForErrors} $aSubstitution");
     }
-    ClassBuilder bCls = b.parent;
+    ClassBuilder bClassBuilder = b.parent;
     Substitution bSubstitution;
-    if (cls != bCls) {
-      assert(substitutions.containsKey(bCls.target),
-          "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
-      bSubstitution = substitutions[bCls.target];
-      debug?.log("${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} "
-          "$bSubstitution");
+    if (classBuilder != bClassBuilder) {
+      assert(
+          substitutions.containsKey(bClassBuilder.cls),
+          "${classBuilder.fullNameForErrors} "
+          "${bClassBuilder.fullNameForErrors}");
+      bSubstitution = substitutions[bClassBuilder.cls];
+      debug?.log("${classBuilder.fullNameForErrors} -> "
+          "${bClassBuilder.fullNameForErrors} $bSubstitution");
     }
-    Procedure aProcedure = a.target;
+    Procedure aProcedure = a.procedure;
     if (b.target is! Procedure) {
       debug?.log("Giving up 1");
       return false;
@@ -662,9 +676,9 @@
     }
 
     if (aReturnType != bReturnType) {
-      if (a.parent == cls && a.returnType == null) {
-        result =
-            inferReturnType(cls, a, bReturnType, hadTypesInferred, hierarchy);
+      if (a.parent == classBuilder && a.returnType == null) {
+        result = inferReturnType(
+            classBuilder, a, bReturnType, hadTypesInferred, hierarchy);
       } else {
         debug?.log("Giving up 6");
         result = false;
@@ -687,9 +701,9 @@
         bType = substitution.substituteType(bType);
       }
       if (aType != bType) {
-        if (a.parent == cls && a.formals[i].type == null) {
-          result = inferParameterType(
-              cls, a, a.formals[i], bType, hadTypesInferred, hierarchy);
+        if (a.parent == classBuilder && a.formals[i].type == null) {
+          result = inferParameterType(classBuilder, a, a.formals[i], bType,
+              hadTypesInferred, hierarchy);
         } else {
           debug?.log("Giving up 8");
           result = false;
@@ -748,9 +762,9 @@
               break;
             }
           }
-          if (a.parent == cls && parameter.type == null) {
+          if (a.parent == classBuilder && parameter.type == null) {
             result = inferParameterType(
-                cls, a, parameter, bType, hadTypesInferred, hierarchy);
+                classBuilder, a, parameter, bType, hadTypesInferred, hierarchy);
           } else {
             debug?.log("Giving up 12");
             result = false;
@@ -793,14 +807,14 @@
       debug?.log("Giving up (not field/procedure: ${bTarget.runtimeType})");
       return false;
     }
-    return a.target.function.returnType == bType;
+    return a.procedure.function.returnType == bType;
   }
 
   bool inferSetterType(ProcedureBuilder a, Builder b) {
     debug?.log(
         "Inferring setter types for ${fullName(a)} based on ${fullName(b)}");
     Member bTarget = b.target;
-    Procedure aProcedure = a.target;
+    Procedure aProcedure = a.procedure;
     VariableDeclaration aParameter =
         aProcedure.function.positionalParameters.single;
     DartType bType;
@@ -853,10 +867,11 @@
     if (b is DelayedMember) {
       for (int i = 0; i < b.declarations.length; i++) {
         hierarchy.overrideChecks
-            .add(new DelayedOverrideCheck(cls, a, b.declarations[i]));
+            .add(new DelayedOverrideCheck(classBuilder, a, b.declarations[i]));
       }
     } else {
-      hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+      hierarchy.overrideChecks
+          .add(new DelayedOverrideCheck(classBuilder, a, b));
     }
   }
 
@@ -880,7 +895,7 @@
         VariableDeclaration parameter =
             bTarget.function.positionalParameters.single;
         // inheritedType = parameter.type;
-        copyFieldCovarianceFromParameter(a.parent, a.target, parameter);
+        copyFieldCovarianceFromParameter(a.parent, a.member, parameter);
         if (!hasExplicitlyTypedFormalParameter(b, 0)) {
           debug?.log("Giving up (type may be inferred)");
           return false;
@@ -890,36 +905,41 @@
         inheritedType = bTarget.function.returnType;
       }
     } else if (bTarget is Field) {
-      copyFieldCovariance(a.parent, a.target, bTarget);
+      copyFieldCovariance(a.parent, a.member, bTarget);
       inheritedType = bTarget.type;
     }
     if (inheritedType == null) {
       debug?.log("Giving up (inheritedType == null)\n${StackTrace.current}");
       return false;
     }
-    ClassBuilder aCls = a.parent;
+    ClassBuilder aClassBuilder = a.parent;
     Substitution aSubstitution;
-    if (cls != aCls) {
-      assert(substitutions.containsKey(aCls.target),
-          "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
-      aSubstitution = substitutions[aCls.target];
-      debug?.log("${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} "
-          "$aSubstitution");
+    if (classBuilder != aClassBuilder) {
+      assert(
+          substitutions.containsKey(aClassBuilder.cls),
+          "${classBuilder.fullNameForErrors} "
+          "${aClassBuilder.fullNameForErrors}");
+      aSubstitution = substitutions[aClassBuilder.cls];
+      debug?.log("${classBuilder.fullNameForErrors} -> "
+          "${aClassBuilder.fullNameForErrors} $aSubstitution");
     }
-    ClassBuilder bCls = b.parent;
+    ClassBuilder bClassBuilder = b.parent;
     Substitution bSubstitution;
-    if (cls != bCls) {
-      assert(substitutions.containsKey(bCls.target),
-          "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
-      bSubstitution = substitutions[bCls.target];
-      debug?.log("${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} "
-          "$bSubstitution");
+    if (classBuilder != bClassBuilder) {
+      assert(
+          substitutions.containsKey(bClassBuilder.cls),
+          "${classBuilder.fullNameForErrors} "
+          "${bClassBuilder.fullNameForErrors}");
+      bSubstitution = substitutions[bClassBuilder.cls];
+      debug?.log("${classBuilder.fullNameForErrors} -> "
+          "${bClassBuilder.fullNameForErrors} $bSubstitution");
     }
     if (bSubstitution != null && inheritedType is! ImplicitFieldType) {
       inheritedType = bSubstitution.substituteType(inheritedType);
     }
 
-    DartType declaredType = a.target.type;
+    Field aField = a.member;
+    DartType declaredType = aField.type;
     if (aSubstitution != null) {
       declaredType = aSubstitution.substituteType(declaredType);
     }
@@ -927,19 +947,19 @@
 
     bool result = false;
     if (a is FieldBuilder) {
-      if (a.parent == cls && a.type == null) {
+      if (a.parent == classBuilder && a.type == null) {
         if (a.hadTypesInferred) {
-          reportCantInferFieldType(cls, a);
+          reportCantInferFieldType(classBuilder, a);
           inheritedType = const InvalidType();
         } else {
           result = true;
           a.hadTypesInferred = true;
         }
         if (inheritedType is ImplicitFieldType) {
-          SourceLibraryBuilder library = cls.library;
+          SourceLibraryBuilder library = classBuilder.library;
           (library.implicitlyTypedFields ??= <FieldBuilder>[]).add(a);
         }
-        a.target.type = inheritedType;
+        a.field.type = inheritedType;
       }
     }
     return result;
@@ -947,7 +967,7 @@
 
   void copyParameterCovariance(Builder parent, VariableDeclaration aParameter,
       VariableDeclaration bParameter) {
-    if (parent == cls) {
+    if (parent == classBuilder) {
       if (bParameter.isCovariant) {
         aParameter.isCovariant = true;
       }
@@ -959,7 +979,7 @@
 
   void copyParameterCovarianceFromField(
       Builder parent, VariableDeclaration aParameter, Field bField) {
-    if (parent == cls) {
+    if (parent == classBuilder) {
       if (bField.isCovariant) {
         aParameter.isCovariant = true;
       }
@@ -970,7 +990,7 @@
   }
 
   void copyFieldCovariance(Builder parent, Field aField, Field bField) {
-    if (parent == cls) {
+    if (parent == classBuilder) {
       if (bField.isCovariant) {
         aField.isCovariant = true;
       }
@@ -982,7 +1002,7 @@
 
   void copyFieldCovarianceFromParameter(
       Builder parent, Field aField, VariableDeclaration bParameter) {
-    if (parent == cls) {
+    if (parent == classBuilder) {
       if (bParameter.isCovariant) {
         aField.isCovariant = true;
       }
@@ -994,7 +1014,7 @@
 
   void copyTypeParameterCovariance(
       Builder parent, TypeParameter aParameter, TypeParameter bParameter) {
-    if (parent == cls) {
+    if (parent == classBuilder) {
       if (bParameter.isGenericCovariantImpl) {
         aParameter.isGenericCovariantImpl = true;
       }
@@ -1004,16 +1024,18 @@
   void reportInheritanceConflict(Builder a, Builder b) {
     String name = a.fullNameForErrors;
     if (a.parent != b.parent) {
-      if (a.parent == cls) {
-        cls.addProblem(messageDeclaredMemberConflictsWithInheritedMember,
-            a.charOffset, name.length,
+      if (a.parent == classBuilder) {
+        classBuilder.addProblem(
+            messageDeclaredMemberConflictsWithInheritedMember,
+            a.charOffset,
+            name.length,
             context: <LocatedMessage>[
               messageDeclaredMemberConflictsWithInheritedMemberCause
                   .withLocation(b.fileUri, b.charOffset, name.length)
             ]);
       } else {
-        cls.addProblem(messageInheritedMembersConflict, cls.charOffset,
-            cls.fullNameForErrors.length,
+        classBuilder.addProblem(messageInheritedMembersConflict,
+            classBuilder.charOffset, classBuilder.fullNameForErrors.length,
             context: inheritedConflictContext(a, b));
       }
     } else if (a.isStatic != b.isStatic) {
@@ -1026,7 +1048,7 @@
         staticMember = b;
         instanceMember = a;
       }
-      cls.library.addProblem(messageStaticAndInstanceConflict,
+      classBuilder.library.addProblem(messageStaticAndInstanceConflict,
           staticMember.charOffset, name.length, staticMember.fileUri,
           context: <LocatedMessage>[
             messageStaticAndInstanceConflictCause.withLocation(
@@ -1048,8 +1070,11 @@
         existing = b;
         duplicate = a;
       }
-      cls.library.addProblem(templateDuplicatedDeclaration.withArguments(name),
-          duplicate.charOffset, name.length, duplicate.fileUri,
+      classBuilder.library.addProblem(
+          templateDuplicatedDeclaration.withArguments(name),
+          duplicate.charOffset,
+          name.length,
+          duplicate.fileUri,
           context: <LocatedMessage>[
             templateDuplicatedDeclarationCause.withArguments(name).withLocation(
                 existing.fileUri, existing.charOffset, name.length)
@@ -1104,7 +1129,7 @@
         ((mergeKind == MergeKind.superclassMembers ||
                 mergeKind == MergeKind.superclassSetters) &&
             target.isAbstract)) {
-      if (isNameVisibleIn(target.name, cls.library)) {
+      if (isNameVisibleIn(target.name, classBuilder.library)) {
         recordAbstractMember(member);
       }
     }
@@ -1117,7 +1142,7 @@
         mergeKind != MergeKind.settersWithMembers &&
         member is DelayedMember &&
         member.isInheritableConflict) {
-      hierarchy.delayedMemberChecks.add(member.withParent(cls));
+      hierarchy.delayedMemberChecks.add(member.withParent(classBuilder));
     }
     return member;
   }
@@ -1132,19 +1157,19 @@
   }
 
   ClassHierarchyNode build() {
-    assert(!cls.isPatch);
+    assert(!classBuilder.isPatch);
     ClassHierarchyNode supernode;
-    if (objectClass != cls.origin) {
-      supernode = hierarchy.getNodeFromType(cls.supertype);
+    if (objectClass != classBuilder.origin) {
+      supernode = hierarchy.getNodeFromType(classBuilder.supertype);
       if (supernode == null) {
         supernode = hierarchy.getNodeFromClass(objectClass);
       }
       assert(supernode != null);
     }
 
-    Scope scope = cls.scope;
-    if (cls.isMixinApplication) {
-      Builder mixin = cls.mixedInType.declaration;
+    Scope scope = classBuilder.scope;
+    if (classBuilder.isMixinApplication) {
+      Builder mixin = classBuilder.mixedInType.declaration;
       inferMixinApplication();
       // recordSupertype(cls.mixedInType);
       while (mixin.isNamedMixinApplication) {
@@ -1203,15 +1228,17 @@
       maxInheritancePath = supernode.maxInheritancePath + 1;
       superclasses = new List<TypeBuilder>(supernode.superclasses.length + 1);
       superclasses.setRange(0, superclasses.length - 1,
-          substSupertypes(cls.supertype, supernode.superclasses));
-      superclasses[superclasses.length - 1] = recordSupertype(cls.supertype);
+          substSupertypes(classBuilder.supertype, supernode.superclasses));
+      superclasses[superclasses.length - 1] =
+          recordSupertype(classBuilder.supertype);
 
-      List<TypeBuilder> directInterfaces = ignoreFunction(cls.interfaces);
-      if (cls.isMixinApplication) {
+      List<TypeBuilder> directInterfaces =
+          ignoreFunction(classBuilder.interfaces);
+      if (classBuilder.isMixinApplication) {
         if (directInterfaces == null) {
-          directInterfaces = <TypeBuilder>[cls.mixedInType];
+          directInterfaces = <TypeBuilder>[classBuilder.mixedInType];
         } else {
-          directInterfaces = <TypeBuilder>[cls.mixedInType]
+          directInterfaces = <TypeBuilder>[classBuilder.mixedInType]
             ..addAll(directInterfaces);
         }
       }
@@ -1223,7 +1250,7 @@
       List<TypeBuilder> superclassInterfaces = supernode.interfaces;
       if (superclassInterfaces != null) {
         superclassInterfaces =
-            substSupertypes(cls.supertype, superclassInterfaces);
+            substSupertypes(classBuilder.supertype, superclassInterfaces);
       }
 
       classMembers = merge(
@@ -1298,7 +1325,7 @@
         merge(classMembers, interfaceSetters, MergeKind.membersWithSetters);
       }
     }
-    if (abstractMembers != null && !cls.isAbstract) {
+    if (abstractMembers != null && !classBuilder.isAbstract) {
       if (!hasNoSuchMethod) {
         reportMissingMembers();
       } else {
@@ -1306,7 +1333,7 @@
       }
     }
     return new ClassHierarchyNode(
-      cls,
+      classBuilder,
       classMembers,
       classSetters,
       interfaceMembers,
@@ -1320,33 +1347,34 @@
 
   TypeBuilder recordSupertype(TypeBuilder supertype) {
     if (supertype is NamedTypeBuilder) {
-      debug?.log("In ${this.cls.fullNameForErrors} "
+      debug?.log("In ${this.classBuilder.fullNameForErrors} "
           "recordSupertype(${supertype.fullNameForErrors})");
       Builder declaration = supertype.declaration;
       if (declaration is! ClassBuilder) return supertype;
-      ClassBuilder cls = declaration;
-      if (cls.isMixinApplication) {
-        recordSupertype(cls.mixedInType);
+      ClassBuilder classBuilder = declaration;
+      if (classBuilder.isMixinApplication) {
+        recordSupertype(classBuilder.mixedInType);
       }
-      List<TypeVariableBuilder> typeVariables = cls.typeVariables;
-      if (typeVariables == null) {
-        substitutions[cls.target] = Substitution.empty;
-        assert(cls.target.typeParameters.isEmpty);
+      List<TypeVariableBuilder> typeVariableBuilders =
+          classBuilder.typeVariables;
+      if (typeVariableBuilders == null) {
+        substitutions[classBuilder.cls] = Substitution.empty;
+        assert(classBuilder.cls.typeParameters.isEmpty);
       } else {
         List<TypeBuilder> arguments =
             supertype.arguments ?? computeDefaultTypeArguments(supertype);
-        if (arguments.length != typeVariables.length) {
+        if (arguments.length != typeVariableBuilders.length) {
           arguments = computeDefaultTypeArguments(supertype);
         }
-        List<DartType> kernelArguments = new List<DartType>(arguments.length);
-        List<TypeParameter> kernelParameters =
+        List<DartType> typeArguments = new List<DartType>(arguments.length);
+        List<TypeParameter> typeParameters =
             new List<TypeParameter>(arguments.length);
         for (int i = 0; i < arguments.length; i++) {
-          kernelParameters[i] = typeVariables[i].target;
-          kernelArguments[i] = arguments[i].build(this.cls.parent);
+          typeParameters[i] = typeVariableBuilders[i].parameter;
+          typeArguments[i] = arguments[i].build(this.classBuilder.parent);
         }
-        substitutions[cls.target] =
-            Substitution.fromPairs(kernelParameters, kernelArguments);
+        substitutions[classBuilder.cls] =
+            Substitution.fromPairs(typeParameters, typeArguments);
       }
     }
     return supertype;
@@ -1359,7 +1387,8 @@
     ClassBuilder cls = declaration;
     List<TypeVariableBuilder> typeVariables = cls.typeVariables;
     if (typeVariables == null) {
-      debug?.log("In ${this.cls.fullNameForErrors} $supertypes aren't substed");
+      debug?.log("In ${this.classBuilder.fullNameForErrors} "
+          "$supertypes aren't substed");
       for (int i = 0; i < supertypes.length; i++) {
         recordSupertype(supertypes[i]);
       }
@@ -1377,11 +1406,13 @@
       TypeBuilder supertype = supertypes[i];
       TypeBuilder substed = recordSupertype(supertype.subst(substitution));
       if (supertype != substed) {
-        debug?.log("In ${this.cls.fullNameForErrors} $supertype -> $substed");
+        debug?.log(
+            "In ${this.classBuilder.fullNameForErrors} $supertype -> $substed");
         result ??= supertypes.toList();
         result[i] = substed;
       } else {
-        debug?.log("In ${this.cls.fullNameForErrors} $supertype isn't substed");
+        debug?.log("In ${this.classBuilder.fullNameForErrors} "
+            "$supertype isn't substed");
       }
     }
     return result ?? supertypes;
@@ -1393,7 +1424,7 @@
     for (int i = 0; i < result.length; ++i) {
       TypeVariableBuilder tv = cls.typeVariables[i];
       result[i] = tv.defaultType ??
-          cls.library.loader.computeTypeBuilder(tv.target.defaultType);
+          cls.library.loader.computeTypeBuilder(tv.parameter.defaultType);
     }
     return result;
   }
@@ -1404,7 +1435,8 @@
     if (node == null) return null;
     int depth = node.depth;
     int myDepth = superclasses.length;
-    if (depth < myDepth && superclasses[depth].declaration == node.cls) {
+    if (depth < myDepth &&
+        superclasses[depth].declaration == node.classBuilder) {
       // This is a potential conflict.
       return superclasses[depth];
     } else {
@@ -1423,7 +1455,7 @@
 
   MergeResult mergeInterfaces(
       ClassHierarchyNode supernode, List<TypeBuilder> interfaces) {
-    debug?.log("mergeInterfaces($cls (${this.cls}) "
+    debug?.log("mergeInterfaces($classBuilder (${this.classBuilder}) "
         "${supernode.interfaces} ${interfaces}");
     List<List<Builder>> memberLists =
         new List<List<Builder>>(interfaces.length + 1);
@@ -1525,7 +1557,7 @@
     for (int i = 0; i < abstractMembers.length; i++) {
       Builder declaration = abstractMembers[i];
       Member target = declaration.target;
-      if (isNameVisibleIn(target.name, cls.library)) {
+      if (isNameVisibleIn(target.name, classBuilder.library)) {
         String name = declaration.fullNameForErrors;
         String parentName = declaration.parent.fullNameForErrors;
         String displayName =
@@ -1542,11 +1574,11 @@
     for (int i = 0; i < names.length; i++) {
       context.add(contextMap[names[i]]);
     }
-    cls.addProblem(
+    classBuilder.addProblem(
         templateMissingImplementationNotAbstract.withArguments(
-            cls.fullNameForErrors, names),
-        cls.charOffset,
-        cls.fullNameForErrors.length,
+            classBuilder.fullNameForErrors, names),
+        classBuilder.charOffset,
+        classBuilder.fullNameForErrors.length,
         context: context);
   }
 
@@ -1612,25 +1644,25 @@
   }
 
   void inferMixinApplication() {
-    Class kernelClass = cls.target;
-    Supertype kernelMixedInType = kernelClass.mixedInType;
-    if (kernelMixedInType == null) return;
-    List<DartType> typeArguments = kernelMixedInType.typeArguments;
+    Class cls = classBuilder.cls;
+    Supertype mixedInType = cls.mixedInType;
+    if (mixedInType == null) return;
+    List<DartType> typeArguments = mixedInType.typeArguments;
     if (typeArguments.isEmpty || typeArguments.first is! UnknownType) return;
     new BuilderMixinInferrer(
-            cls,
+            classBuilder,
             hierarchy.coreTypes,
             new TypeBuilderConstraintGatherer(
-                hierarchy, kernelMixedInType.classNode.typeParameters))
-        .infer(kernelClass);
+                hierarchy, mixedInType.classNode.typeParameters))
+        .infer(cls);
     List<TypeBuilder> inferredArguments =
         new List<TypeBuilder>(typeArguments.length);
     for (int i = 0; i < typeArguments.length; i++) {
       inferredArguments[i] =
           hierarchy.loader.computeTypeBuilder(typeArguments[i]);
     }
-    NamedTypeBuilder mixedInType = cls.mixedInType;
-    mixedInType.arguments = inferredArguments;
+    NamedTypeBuilder mixedInTypeBuilder = classBuilder.mixedInType;
+    mixedInTypeBuilder.arguments = inferredArguments;
   }
 
   /// The class Function from dart:core is supposed to be ignored when used as
@@ -1638,8 +1670,8 @@
   List<TypeBuilder> ignoreFunction(List<TypeBuilder> interfaces) {
     if (interfaces == null) return null;
     for (int i = 0; i < interfaces.length; i++) {
-      ClassBuilder cls = getClass(interfaces[i]);
-      if (cls != null && cls.target == hierarchy.functionKernelClass) {
+      ClassBuilder classBuilder = getClass(interfaces[i]);
+      if (classBuilder != null && classBuilder.cls == hierarchy.functionClass) {
         if (interfaces.length == 1) {
           return null;
         } else {
@@ -1655,7 +1687,7 @@
 
 class ClassHierarchyNode {
   /// The class corresponding to this hierarchy node.
-  final ClassBuilder cls;
+  final ClassBuilder classBuilder;
 
   /// All the members of this class including [classMembers] of its
   /// superclasses. The members are sorted by [compareDeclarations].
@@ -1678,15 +1710,15 @@
   /// This may be null, in which case [classSetters] is the interface setters.
   final List<Builder> interfaceSetters;
 
-  /// All superclasses of [cls] excluding itself. The classes are sorted by
-  /// depth from the root (Object) in ascending order.
+  /// All superclasses of [classBuilder] excluding itself. The classes are
+  /// sorted by depth from the root (Object) in ascending order.
   final List<TypeBuilder> superclasses;
 
-  /// The list of all classes implemented by [cls] and its supertypes excluding
-  /// any classes from [superclasses].
+  /// The list of all classes implemented by [classBuilder] and its supertypes
+  /// excluding any classes from [superclasses].
   final List<TypeBuilder> interfaces;
 
-  /// The longest inheritance path from [cls] to `Object`.
+  /// The longest inheritance path from [classBuilder] to `Object`.
   final int maxInheritancePath;
 
   int get depth => superclasses.length;
@@ -1694,7 +1726,7 @@
   final bool hasNoSuchMethod;
 
   ClassHierarchyNode(
-      this.cls,
+      this.classBuilder,
       this.classMembers,
       this.classSetters,
       this.interfaceMembers,
@@ -1704,7 +1736,7 @@
       this.maxInheritancePath,
       this.hasNoSuchMethod);
 
-  /// Returns a list of all supertypes of [cls], including this node.
+  /// Returns a list of all supertypes of [classBuilder], including this node.
   List<ClassHierarchyNode> computeAllSuperNodes(
       ClassHierarchyBuilder hierarchy) {
     List<ClassHierarchyNode> result = new List<ClassHierarchyNode>(
@@ -1728,7 +1760,7 @@
   String toString([StringBuffer sb]) {
     sb ??= new StringBuffer();
     sb
-      ..write(cls.fullNameForErrors)
+      ..write(classBuilder.fullNameForErrors)
       ..writeln(":");
     if (maxInheritancePath != this.depth) {
       sb
@@ -1914,19 +1946,19 @@
       : super.subclassing(typeParameters);
 
   @override
-  Class get objectClass => hierarchy.objectKernelClass;
+  Class get objectClass => hierarchy.objectClass;
 
   @override
-  Class get functionClass => hierarchy.functionKernelClass;
+  Class get functionClass => hierarchy.functionClass;
 
   @override
-  Class get futureClass => hierarchy.futureKernelClass;
+  Class get futureClass => hierarchy.futureClass;
 
   @override
-  Class get futureOrClass => hierarchy.futureOrKernelClass;
+  Class get futureOrClass => hierarchy.futureOrClass;
 
   @override
-  Class get nullClass => hierarchy.nullKernelClass;
+  Class get nullClass => hierarchy.nullClass;
 
   @override
   InterfaceType get nullType => nullClass.rawType;
@@ -1959,7 +1991,7 @@
 
   @override
   InterfaceType futureType(DartType type) {
-    return new InterfaceType(hierarchy.futureKernelClass, <DartType>[type]);
+    return new InterfaceType(hierarchy.futureClass, <DartType>[type]);
   }
 
   @override
@@ -1975,24 +2007,24 @@
 }
 
 class DelayedOverrideCheck {
-  final ClassBuilder cls;
+  final ClassBuilder classBuilder;
   final Builder a;
   final Builder b;
 
-  const DelayedOverrideCheck(this.cls, this.a, this.b);
+  const DelayedOverrideCheck(this.classBuilder, this.a, this.b);
 
   void check(ClassHierarchyBuilder hierarchy) {
     void callback(
         Member declaredMember, Member interfaceMember, bool isSetter) {
-      cls.checkOverride(
+      classBuilder.checkOverride(
           hierarchy.types, declaredMember, interfaceMember, isSetter, callback,
-          isInterfaceCheck: !cls.isMixinApplication);
+          isInterfaceCheck: !classBuilder.isMixinApplication);
     }
 
     Builder a = this.a;
     debug?.log("Delayed override check of ${fullName(a)} "
-        "${fullName(b)} wrt. ${cls.fullNameForErrors}");
-    if (cls == a.parent) {
+        "${fullName(b)} wrt. ${classBuilder.fullNameForErrors}");
+    if (classBuilder == a.parent) {
       if (a is ProcedureBuilder) {
         if (a.isGetter && !hasExplicitReturnType(a)) {
           DartType type;
@@ -2009,10 +2041,11 @@
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        cls.cls.thisType, b.target.enclosingClass))
+                        classBuilder.cls.thisType, b.target.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isSetter) {
-              inferReturnType(cls, a, type, a.hadTypesInferred, hierarchy);
+              inferReturnType(
+                  classBuilder, a, type, a.hadTypesInferred, hierarchy);
             }
           }
         } else if (a.isSetter && !hasExplicitlyTypedFormalParameter(a, 0)) {
@@ -2030,10 +2063,10 @@
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        cls.cls.thisType, b.target.enclosingClass))
+                        classBuilder.cls.thisType, b.target.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isGetter) {
-              inferParameterType(cls, a, a.formals.single, type,
+              inferParameterType(classBuilder, a, a.formals.single, type,
                   a.hadTypesInferred, hierarchy);
             }
           }
@@ -2054,21 +2087,21 @@
         if (type != null) {
           type = Substitution.fromInterfaceType(
                   hierarchy.getKernelTypeAsInstanceOf(
-                      cls.cls.thisType, b.target.enclosingClass))
+                      classBuilder.cls.thisType, b.target.enclosingClass))
               .substituteType(type);
-          if (type != a.target.type) {
+          if (type != a.field.type) {
             if (a.hadTypesInferred) {
               if (b.isSetter &&
                   (!impliesSetter(a) ||
-                      hierarchy.types.isSubtypeOfKernel(type, a.target.type))) {
-                type = a.target.type;
+                      hierarchy.types.isSubtypeOfKernel(type, a.field.type))) {
+                type = a.field.type;
               } else {
-                reportCantInferFieldType(cls, a);
+                reportCantInferFieldType(classBuilder, a);
                 type = const InvalidType();
               }
             }
             debug?.log("Inferred type ${type} for ${fullName(a)}");
-            a.target.type = type;
+            a.field.type = type;
           }
         }
         a.hadTypesInferred = true;
@@ -2498,18 +2531,18 @@
       wasHandled: true);
 }
 
-bool inferReturnType(ClassBuilder cls, ProcedureBuilder member, DartType type,
-    bool hadTypesInferred, ClassHierarchyBuilder hierarchy) {
-  if (type == member.target.function.returnType) return true;
+bool inferReturnType(ClassBuilder cls, ProcedureBuilder procedureBuilder,
+    DartType type, bool hadTypesInferred, ClassHierarchyBuilder hierarchy) {
+  if (type == procedureBuilder.procedure.function.returnType) return true;
   bool result = true;
   if (hadTypesInferred) {
-    reportCantInferReturnType(cls, member, hierarchy);
+    reportCantInferReturnType(cls, procedureBuilder, hierarchy);
     type = const InvalidType();
     result = false;
   } else {
-    member.hadTypesInferred = true;
+    procedureBuilder.hadTypesInferred = true;
   }
-  member.target.function.returnType = type;
+  procedureBuilder.procedure.function.returnType = type;
   return result;
 }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index 84e251f..21ba143 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -50,10 +50,10 @@
   }
 
   @override
-  accept(ExpressionVisitor<Object> v) => v.defaultExpression(this);
+  R accept<R>(ExpressionVisitor<R> v) => v.defaultExpression(this);
 
   @override
-  accept1(ExpressionVisitor1<Object, Object> v, arg) =>
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.defaultExpression(this, arg);
 }
 
@@ -80,7 +80,7 @@
   @override
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
@@ -108,15 +108,15 @@
   @override
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept(v);
+      then = then.accept<TreeNode>(v);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept(v);
+      otherwise = otherwise.accept<TreeNode>(v);
       otherwise?.parent = this;
     }
   }
@@ -148,12 +148,12 @@
   transformChildren(Transformer v) {
     transformList(variables, v, this);
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     transformList(updates, v, this);
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -188,23 +188,23 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept(v);
+      iterable = iterable.accept<TreeNode>(v);
       iterable?.parent = this;
     }
     if (prologue != null) {
-      prologue = prologue.accept(v);
+      prologue = prologue.accept<TreeNode>(v);
       prologue?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     if (problem != null) {
-      problem = problem.accept(v);
+      problem = problem.accept<TreeNode>(v);
       problem?.parent = this;
     }
   }
@@ -213,26 +213,26 @@
 mixin ControlFlowMapEntry implements MapEntry {
   @override
   Expression get key {
-    throw UnsupportedError('ControlFlowMapEntry.key getter');
+    throw new UnsupportedError('ControlFlowMapEntry.key getter');
   }
 
   @override
   void set key(Expression expr) {
-    throw UnsupportedError('ControlFlowMapEntry.key setter');
+    throw new UnsupportedError('ControlFlowMapEntry.key setter');
   }
 
   @override
   Expression get value {
-    throw UnsupportedError('ControlFlowMapEntry.value getter');
+    throw new UnsupportedError('ControlFlowMapEntry.value getter');
   }
 
   @override
   void set value(Expression expr) {
-    throw UnsupportedError('ControlFlowMapEntry.value setter');
+    throw new UnsupportedError('ControlFlowMapEntry.value setter');
   }
 
   @override
-  accept(TreeVisitor<Object> v) => v.defaultTreeNode(this);
+  R accept<R>(TreeVisitor<R> v) => v.defaultTreeNode(this);
 }
 
 /// A spread element in a map literal.
@@ -258,7 +258,7 @@
   @override
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
@@ -286,15 +286,15 @@
   @override
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept(v);
+      then = then.accept<TreeNode>(v);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept(v);
+      otherwise = otherwise.accept<TreeNode>(v);
       otherwise?.parent = this;
     }
   }
@@ -326,12 +326,12 @@
   transformChildren(Transformer v) {
     transformList(variables, v, this);
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     transformList(updates, v, this);
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -366,23 +366,23 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept(v);
+      iterable = iterable.accept<TreeNode>(v);
       iterable?.parent = this;
     }
     if (prologue != null) {
-      prologue = prologue.accept(v);
+      prologue = prologue.accept<TreeNode>(v);
       prologue?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     if (problem != null) {
-      problem = problem.accept(v);
+      problem = problem.accept<TreeNode>(v);
       problem?.parent = this;
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index b6c81d7..73b8e87 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -42,6 +42,7 @@
         messageConstEvalNotListOrSetInSpread,
         messageConstEvalNotMapInSpread,
         messageConstEvalNullValue,
+        messageConstEvalStartingPoint,
         messageConstEvalUnevaluated,
         noLength,
         templateConstEvalDeferredLibrary,
@@ -117,14 +118,14 @@
 
 class JavaScriptIntConstant extends DoubleConstant {
   final BigInt bigIntValue;
-  JavaScriptIntConstant(int value) : this.fromBigInt(BigInt.from(value));
+  JavaScriptIntConstant(int value) : this.fromBigInt(new BigInt.from(value));
   JavaScriptIntConstant.fromDouble(double value)
-      : bigIntValue = BigInt.from(value),
+      : bigIntValue = new BigInt.from(value),
         super(value);
   JavaScriptIntConstant.fromBigInt(this.bigIntValue)
       : super(bigIntValue.toDouble());
   JavaScriptIntConstant.fromUInt64(int value)
-      : this.fromBigInt(BigInt.from(value).toUnsigned(64));
+      : this.fromBigInt(new BigInt.from(value).toUnsigned(64));
 
   DartType getType(TypeEnvironment types) => types.intType;
 
@@ -212,7 +213,7 @@
   Procedure visitProcedure(Procedure node) {
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
-      node.function = node.function.accept(this)..parent = node;
+      node.function = node.function.accept<TreeNode>(this)..parent = node;
     });
     return node;
   }
@@ -222,7 +223,7 @@
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       transformList(node.initializers, this, node);
-      node.function = node.function.accept(this)..parent = node;
+      node.function = node.function.accept<TreeNode>(this)..parent = node;
     });
     return node;
   }
@@ -295,7 +296,7 @@
       }
     }
     if (node.body != null) {
-      node.body = node.body.accept(this)..parent = node;
+      node.body = node.body.accept<TreeNode>(this)..parent = node;
     }
     return node;
   }
@@ -321,7 +322,8 @@
           }
         }
       } else {
-        node.initializer = node.initializer.accept(this)..parent = node;
+        node.initializer = node.initializer.accept<TreeNode>(this)
+          ..parent = node;
       }
     }
     return node;
@@ -343,7 +345,8 @@
       } else {
         transformAnnotations(node.annotations, node);
         if (node.initializer != null) {
-          node.initializer = node.initializer.accept(this)..parent = node;
+          node.initializer = node.initializer.accept<TreeNode>(this)
+            ..parent = node;
         }
       }
       return node;
@@ -589,34 +592,43 @@
     lazyDepth = 0;
     try {
       Constant result = _evaluateSubexpression(node);
-      if (errorOnUnevaluatedConstant && result is UnevaluatedConstant) {
-        return report(node, messageConstEvalUnevaluated);
+      if (result is UnevaluatedConstant) {
+        if (errorOnUnevaluatedConstant) {
+          return report(node, messageConstEvalUnevaluated);
+        }
+        return new UnevaluatedConstant(
+            removeRedundantFileUriExpressions(result.expression));
       }
       return result;
     } on _AbortDueToError catch (e) {
       final Uri uri = getFileUri(e.node);
       final int fileOffset = getFileOffset(uri, e.node);
-      final LocatedMessage locatedMessage =
+      final LocatedMessage locatedMessageActualError =
           e.message.withLocation(uri, fileOffset, noLength);
 
-      final List<LocatedMessage> contextMessages = <LocatedMessage>[];
+      final List<LocatedMessage> contextMessages = <LocatedMessage>[
+        locatedMessageActualError
+      ];
       if (e.context != null) contextMessages.addAll(e.context);
       for (final TreeNode node in contextChain) {
+        if (node == e.node) continue;
         final Uri uri = getFileUri(node);
         final int fileOffset = getFileOffset(uri, node);
         contextMessages.add(
             messageConstEvalContext.withLocation(uri, fileOffset, noLength));
       }
-      errorReporter.report(locatedMessage, contextMessages);
+
+      {
+        final Uri uri = getFileUri(node);
+        final int fileOffset = getFileOffset(uri, node);
+        final LocatedMessage locatedMessage = messageConstEvalStartingPoint
+            .withLocation(uri, fileOffset, noLength);
+        errorReporter.report(locatedMessage, contextMessages);
+      }
       return new UnevaluatedConstant(new InvalidExpression(e.message.message));
     } on _AbortDueToInvalidExpression catch (e) {
-      // TODO(askesc): Copy position from erroneous node.
-      // Currently not possible, as it might be in a different file.
-      // Can be done if we add an explicit URI to InvalidExpression.
-      InvalidExpression invalid = new InvalidExpression(e.message);
-      if (invalid.fileOffset == TreeNode.noOffset) {
-        invalid.fileOffset = node.fileOffset;
-      }
+      InvalidExpression invalid = new InvalidExpression(e.message)
+        ..fileOffset = node.fileOffset;
       errorReporter.reportInvalidExpression(invalid);
       return new UnevaluatedConstant(invalid);
     }
@@ -636,8 +648,13 @@
   /// Produce an unevaluated constant node for an expression.
   Constant unevaluated(Expression original, Expression replacement) {
     replacement.fileOffset = original.fileOffset;
-    // TODO(askesc,johnniwinther): Preserve fileUri on [replacement].
-    return new UnevaluatedConstant(replacement);
+    return new UnevaluatedConstant(
+        new FileUriExpression(replacement, getFileUri(original))
+          ..fileOffset = original.fileOffset);
+  }
+
+  Expression removeRedundantFileUriExpressions(Expression node) {
+    return node.accept(new RedundantFileUriExpressionRemover()) as Expression;
   }
 
   /// Extract an expression from a (possibly unevaluated) constant to become
@@ -762,6 +779,11 @@
   }
 
   @override
+  Constant visitFileUriExpression(FileUriExpression node) {
+    return _evaluateSubexpression(node.expression);
+  }
+
+  @override
   Constant visitNullLiteral(NullLiteral node) => nullConstant;
 
   @override
@@ -2299,6 +2321,23 @@
   }
 }
 
+class RedundantFileUriExpressionRemover extends Transformer {
+  Uri currentFileUri = null;
+
+  TreeNode visitFileUriExpression(FileUriExpression node) {
+    if (node.fileUri == currentFileUri) {
+      return node.expression.accept(this);
+    } else {
+      Uri oldFileUri = currentFileUri;
+      currentFileUri = node.fileUri;
+      node.expression = node.expression.accept(this) as Expression
+        ..parent = node;
+      currentFileUri = oldFileUri;
+      return node;
+    }
+  }
+}
+
 // Used as control-flow to abort the current evaluation.
 class _AbortDueToError {
   final TreeNode node;
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 d9ba7e9..69994cc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -29,36 +29,13 @@
 
 import '../constant_context.dart' show ConstantContext;
 
-import '../builder/builder.dart' show PrefixBuilder, TypeDeclarationBuilder;
+import '../builder/builder.dart'
+    show NullabilityBuilder, PrefixBuilder, TypeDeclarationBuilder;
 import '../builder/declaration_builder.dart';
+import '../builder/extension_builder.dart';
+import '../builder/member_builder.dart';
 
-import '../fasta_codes.dart'
-    show
-        LocatedMessage,
-        Message,
-        Template,
-        messageCannotAssignToSuper,
-        messageCannotAssignToParenthesizedExpression,
-        messageCantUsePrefixAsExpression,
-        messageCantUsePrefixWithNullAware,
-        messageIllegalAssignmentToNonAssignable,
-        messageInvalidInitializer,
-        messageInvalidUseOfNullAwareAccess,
-        messageLoadLibraryTakesNoArguments,
-        messageNotAConstantExpression,
-        messageNotAnLvalue,
-        messageSuperAsExpression,
-        noLength,
-        templateCantUseDeferredPrefixAsConstant,
-        templateConstructorNotFound,
-        templateDeferredTypeAnnotation,
-        templateMissingExplicitTypeArguments,
-        templateNotConstantExpression,
-        templateNotAPrefixInTypeAnnotation,
-        templateNotAType,
-        templateSuperclassHasNoConstructor,
-        templateThisOrSuperAccessInFieldInitializer,
-        templateUnresolvedPrefixInTypeAnnotation;
+import '../fasta_codes.dart';
 
 import '../names.dart'
     show
@@ -82,7 +59,7 @@
 
 import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
 
-import '../problems.dart' show unhandled, unsupported;
+import '../problems.dart';
 
 import '../scope.dart';
 
@@ -133,7 +110,8 @@
         SuperPropertyGetJudgment,
         SyntheticWrapper,
         VariableDeclarationJudgment,
-        VariableGetJudgment;
+        VariableGetJudgment,
+        getExplicitTypeArguments;
 
 /// A generator represents a subexpression for which we can't yet build an
 /// expression because we don't yet know the context in which it's used.
@@ -153,7 +131,9 @@
   /// A token that defines a position subexpression that being built.
   final Token token;
 
-  Generator(this._helper, this.token);
+  final int fileOffset;
+
+  Generator(this._helper, this.token) : fileOffset = offsetForToken(token);
 
   /// Easy access to the [Forest] factory object.
   Forest get _forest => _helper.forest;
@@ -303,8 +283,7 @@
     complexAssignment?.isPostIncDec = true;
     VariableDeclarationJudgment dummy =
         new VariableDeclarationJudgment.forValue(
-            _makeWrite(combiner, true, complexAssignment),
-            _helper.functionNestingLevel);
+            _makeWrite(combiner, true, complexAssignment));
     return _finish(
         makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
   }
@@ -315,12 +294,12 @@
   Expression _makeInvalidRead() {
     return _helper.wrapSyntheticExpression(
         _helper.throwNoSuchMethodError(
-            _forest.createNullLiteral(token),
+            _forest.createNullLiteral(fileOffset),
             _plainNameForRead,
             _forest.createArgumentsEmpty(noLocation),
-            offsetForToken(token),
+            fileOffset,
             isGetter: true),
-        offsetForToken(token));
+        fileOffset);
   }
 
   /// Returns a [Expression] representing a compile-time error wrapping
@@ -330,12 +309,12 @@
   Expression _makeInvalidWrite(Expression value) {
     return _helper.wrapSyntheticExpression(
         _helper.throwNoSuchMethodError(
-            _forest.createNullLiteral(token),
+            _forest.createNullLiteral(fileOffset),
             _plainNameForRead,
-            _forest.createArguments(<Expression>[value], noLocation),
-            offsetForToken(token),
+            _forest.createArguments(noLocation, <Expression>[value]),
+            fileOffset,
             isSetter: true),
-        offsetForToken(token));
+        fileOffset);
   }
 
   /// Returns an [Expression] the reads this subexpression.
@@ -409,11 +388,10 @@
   Expression buildForEffect() => buildSimpleRead();
 
   Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    int offset = offsetForToken(token);
     return _helper.buildInvalidInitializer(
         _helper.desugarSyntheticExpression(_helper.buildProblem(
-            messageInvalidInitializer, offset, lengthForToken(token))),
-        offset);
+            messageInvalidInitializer, fileOffset, lengthForToken(token))),
+        fileOffset);
   }
 
   /// Returns an expression, generator or initializer for an invocation of this
@@ -442,7 +420,7 @@
       if (_helper.constantContext != ConstantContext.none &&
           send.name != lengthName) {
         _helper.addProblem(
-            messageNotAConstantExpression, offsetForToken(token), token.length);
+            messageNotAConstantExpression, fileOffset, token.length);
       }
       return PropertyAccessGenerator.make(_helper, send.token,
           buildSimpleRead(), send.name, null, null, isNullAware);
@@ -454,13 +432,15 @@
   ///
   /// The type arguments have not been resolved and should be resolved to
   /// create a [TypeBuilder] for a valid type.
-  TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
-    NamedTypeBuilder result = new NamedTypeBuilder(token.lexeme, null);
+  TypeBuilder buildTypeWithResolvedArguments(
+      NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
+    NamedTypeBuilder result =
+        new NamedTypeBuilder(token.lexeme, nullabilityBuilder, null);
     Message message = templateNotAType.withArguments(token.lexeme);
-    _helper.library.addProblem(
-        message, offsetForToken(token), lengthForToken(token), _uri);
-    result.bind(result.buildInvalidType(message.withLocation(
-        _uri, offsetForToken(token), lengthForToken(token))));
+    _helper.libraryBuilder
+        .addProblem(message, fileOffset, lengthForToken(token), _uri);
+    result.bind(result.buildInvalidType(
+        message.withLocation(_uri, fileOffset, lengthForToken(token))));
     return result;
   }
 
@@ -482,14 +462,14 @@
     }
     return _helper.wrapInvalidConstructorInvocation(
         _helper.throwNoSuchMethodError(
-            _forest.createNullLiteral(token),
+            _forest.createNullLiteral(fileOffset),
             _helper.constructorNameForDiagnostics(name,
                 className: _plainNameForRead),
             arguments,
             nameToken.charOffset),
         null,
         arguments,
-        offsetForToken(token));
+        fileOffset);
   }
 
   void printOn(StringSink sink);
@@ -498,7 +478,7 @@
     StringBuffer buffer = new StringBuffer();
     buffer.write(_debugName);
     buffer.write("(offset: ");
-    buffer.write("${offsetForToken(token)}");
+    buffer.write("${fileOffset}");
     printOn(buffer);
     buffer.write(")");
     return "$buffer";
@@ -542,7 +522,7 @@
         ?.getFactForAccess(variable, _helper.functionNestingLevel);
     TypePromotionScope scope = _helper.typePromoter?.currentScope;
     VariableGetJudgment read = new VariableGetJudgment(variable, fact, scope)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -560,8 +540,7 @@
         complexAssignment.write = write;
       }
     } else {
-      write = new VariableSet(variable, value)
-        ..fileOffset = offsetForToken(token);
+      write = new VariableSet(variable, value)..fileOffset = fileOffset;
       complexAssignment?.write = write;
     }
     return write;
@@ -577,7 +556,7 @@
   @override
   ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
     return SyntheticWrapper.wrapVariableAssignment(rhs)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   @override
@@ -634,8 +613,7 @@
 
   receiverAccess() {
     _receiverVariable ??= new VariableDeclaration.forValue(receiver);
-    return new VariableGet(_receiverVariable)
-      ..fileOffset = offsetForToken(token);
+    return new VariableGet(_receiverVariable)..fileOffset = fileOffset;
   }
 
   @override
@@ -664,15 +642,14 @@
 
   @override
   Expression _makeSimpleRead() {
-    return new PropertyGet(receiver, name, getter)
-      ..fileOffset = offsetForToken(token);
+    return new PropertyGet(receiver, name, getter)..fileOffset = fileOffset;
   }
 
   @override
   Expression _makeSimpleWrite(Expression value, bool voidContext,
       ComplexAssignmentJudgment complexAssignment) {
     PropertySet write = new PropertySet(receiver, name, value, setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -680,7 +657,7 @@
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     PropertyGet read = new PropertyGet(receiverAccess(), name, getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -689,7 +666,7 @@
   Expression _makeWrite(Expression value, bool voidContext,
       ComplexAssignmentJudgment complexAssignment) {
     PropertySet write = new PropertySet(receiverAccess(), name, value, setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -785,11 +762,11 @@
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     if (getter == null) {
-      _helper.warnUnresolvedGet(name, offsetForToken(token));
+      _helper.warnUnresolvedGet(name, fileOffset);
     }
     PropertyGet read =
         new PropertyGet(_forest.createThisExpression(token), name, getter)
-          ..fileOffset = offsetForToken(token);
+          ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -798,11 +775,11 @@
   Expression _makeWrite(Expression value, bool voidContext,
       ComplexAssignmentJudgment complexAssignment) {
     if (setter == null) {
-      _helper.warnUnresolvedSet(name, offsetForToken(token));
+      _helper.warnUnresolvedSet(name, fileOffset);
     }
     PropertySet write = new PropertySet(
         _forest.createThisExpression(token), name, value, setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -874,7 +851,7 @@
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     PropertyGet read = new PropertyGet(receiverAccess(), name, getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -883,7 +860,7 @@
   Expression _makeWrite(Expression value, bool voidContext,
       ComplexAssignmentJudgment complexAssignment) {
     PropertySet write = new PropertySet(receiverAccess(), name, value, setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -891,14 +868,13 @@
   @override
   Expression _finish(
       Expression body, ComplexAssignmentJudgment complexAssignment) {
-    int offset = offsetForToken(token);
     Expression nullAwareGuard = _forest.createConditionalExpression(
-        buildIsNull(receiverAccess(), offset, _helper),
+        buildIsNull(receiverAccess(), fileOffset, _helper),
         null,
-        _forest.createNullLiteral(null)..fileOffset = offset,
+        _forest.createNullLiteral(null)..fileOffset = fileOffset,
         null,
         body)
-      ..fileOffset = offset;
+      ..fileOffset = fileOffset;
     if (complexAssignment != null) {
       body = makeLet(receiver, nullAwareGuard);
       if (_helper.legacyMode) return body;
@@ -908,7 +884,7 @@
       return kernelPropertyAssign;
     } else {
       return new NullAwarePropertyGetJudgment(receiver, nullAwareGuard)
-        ..fileOffset = offset;
+        ..fileOffset = fileOffset;
     }
   }
 
@@ -959,12 +935,12 @@
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     if (getter == null) {
-      _helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
+      _helper.warnUnresolvedGet(name, fileOffset, isSuper: true);
     }
     // TODO(ahe): Use [DirectPropertyGet] when possible.
     SuperPropertyGetJudgment read =
         new SuperPropertyGetJudgment(name, interfaceTarget: getter)
-          ..fileOffset = offsetForToken(token);
+          ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -973,11 +949,11 @@
   Expression _makeWrite(Expression value, bool voidContext,
       ComplexAssignmentJudgment complexAssignment) {
     if (setter == null) {
-      _helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
+      _helper.warnUnresolvedSet(name, fileOffset, isSuper: true);
     }
     // TODO(ahe): Use [DirectPropertySet] when possible.
     SuperPropertySet write = new SuperPropertySet(name, value, setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1043,23 +1019,22 @@
 
   Expression indexAccess() {
     indexVariable ??= new VariableDeclaration.forValue(index);
-    return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
+    return new VariableGet(indexVariable)..fileOffset = fileOffset;
   }
 
   Expression receiverAccess() {
     // We cannot reuse the receiver if it is a variable since it might be
     // reassigned in the index expression.
     receiverVariable ??= new VariableDeclaration.forValue(receiver);
-    return new VariableGet(receiverVariable)
-      ..fileOffset = offsetForToken(token);
+    return new VariableGet(receiverVariable)..fileOffset = fileOffset;
   }
 
   @override
   Expression _makeSimpleRead() {
     MethodInvocationJudgment read = new MethodInvocationJudgment(receiver,
-        indexGetName, _forest.createArguments(<Expression>[index], token),
+        indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
         interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     return read;
   }
 
@@ -1070,9 +1045,9 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         receiver,
         indexSetName,
-        _forest.createArguments(<Expression>[index, value], token),
+        _forest.createArguments(fileOffset, <Expression>[index, value]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1082,9 +1057,9 @@
     MethodInvocationJudgment read = new MethodInvocationJudgment(
         receiverAccess(),
         indexGetName,
-        _forest.createArguments(<Expression>[indexAccess()], token),
+        _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
         interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -1096,9 +1071,9 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         receiverAccess(),
         indexSetName,
-        _forest.createArguments(<Expression>[indexAccess(), value], token),
+        _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1113,14 +1088,13 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         receiverAccess(),
         indexSetName,
-        _forest.createArguments(
-            <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+        _forest.createArguments(fileOffset,
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     VariableDeclarationJudgment dummy =
-        new VariableDeclarationJudgment.forValue(
-            write, _helper.functionNestingLevel);
+        new VariableDeclarationJudgment.forValue(write);
     return makeLet(
         valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
   }
@@ -1128,11 +1102,10 @@
   @override
   Expression _finish(
       Expression body, ComplexAssignmentJudgment complexAssignment) {
-    int offset = offsetForToken(token);
     return super._finish(
-        makeLet(
-            receiverVariable, makeLet(indexVariable, body)..fileOffset = offset)
-          ..fileOffset = offset,
+        makeLet(receiverVariable,
+            makeLet(indexVariable, body)..fileOffset = fileOffset)
+          ..fileOffset = fileOffset,
         complexAssignment);
   }
 
@@ -1213,10 +1186,10 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         _forest.createThisExpression(token),
         indexSetName,
-        _forest.createArguments(
-            <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+        _forest.createArguments(fileOffset,
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     VariableDeclaration dummy = new VariableDeclaration.forValue(write);
     return makeLet(
@@ -1226,9 +1199,9 @@
   @override
   Expression _makeSimpleRead() {
     return new MethodInvocationJudgment(_forest.createThisExpression(token),
-        indexGetName, _forest.createArguments(<Expression>[index], token),
+        indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
         interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   @override
@@ -1238,9 +1211,9 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         _forest.createThisExpression(token),
         indexSetName,
-        _forest.createArguments(<Expression>[index, value], token),
+        _forest.createArguments(fileOffset, <Expression>[index, value]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1250,9 +1223,9 @@
     MethodInvocationJudgment read = new MethodInvocationJudgment(
         _forest.createThisExpression(token),
         indexGetName,
-        _forest.createArguments(<Expression>[indexAccess()], token),
+        _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
         interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -1264,9 +1237,9 @@
     MethodInvocationJudgment write = new MethodInvocationJudgment(
         _forest.createThisExpression(token),
         indexSetName,
-        _forest.createArguments(<Expression>[indexAccess(), value], token),
+        _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
         interfaceTarget: setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1328,15 +1301,14 @@
       Expression value, ComplexAssignmentJudgment complexAssignment) {
     VariableDeclaration valueVariable = new VariableDeclaration.forValue(value);
     if (setter == null) {
-      _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
+      _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
     }
     SuperMethodInvocation write = new SuperMethodInvocation(
         indexSetName,
-        _forest.createArguments(
-            <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+        _forest.createArguments(fileOffset,
+            <Expression>[indexAccess(), new VariableGet(valueVariable)]),
         setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     VariableDeclaration dummy = new VariableDeclaration.forValue(write);
     return makeLet(
@@ -1346,14 +1318,13 @@
   @override
   Expression _makeSimpleRead() {
     if (getter == null) {
-      _helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
-          isSuper: true);
+      _helper.warnUnresolvedMethod(indexGetName, fileOffset, isSuper: true);
     }
     // TODO(ahe): Use [DirectMethodInvocation] when possible.
     return new SuperMethodInvocationJudgment(
-        indexGetName, _forest.createArguments(<Expression>[index], token),
+        indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
         interfaceTarget: getter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   @override
@@ -1361,12 +1332,11 @@
       ComplexAssignmentJudgment complexAssignment) {
     if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
     if (setter == null) {
-      _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
+      _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
     }
     SuperMethodInvocation write = new SuperMethodInvocation(indexSetName,
-        _forest.createArguments(<Expression>[index, value], token), setter)
-      ..fileOffset = offsetForToken(token);
+        _forest.createArguments(fileOffset, <Expression>[index, value]), setter)
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1374,12 +1344,13 @@
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     if (getter == null) {
-      _helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
-          isSuper: true);
+      _helper.warnUnresolvedMethod(indexGetName, fileOffset, isSuper: true);
     }
-    SuperMethodInvocation read = new SuperMethodInvocation(indexGetName,
-        _forest.createArguments(<Expression>[indexAccess()], token), getter)
-      ..fileOffset = offsetForToken(token);
+    SuperMethodInvocation read = new SuperMethodInvocation(
+        indexGetName,
+        _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
+        getter)
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -1389,14 +1360,13 @@
       ComplexAssignmentJudgment complexAssignment) {
     if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
     if (setter == null) {
-      _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
-          isSuper: true);
+      _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
     }
     SuperMethodInvocation write = new SuperMethodInvocation(
         indexSetName,
-        _forest.createArguments(<Expression>[indexAccess(), value], token),
+        _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
         setter)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.write = write;
     return write;
   }
@@ -1404,8 +1374,7 @@
   @override
   Expression _finish(
       Expression body, ComplexAssignmentJudgment complexAssignment) {
-    return super._finish(
-        makeLet(indexVariable, body)..fileOffset = offsetForToken(token),
+    return super._finish(makeLet(indexVariable, body)..fileOffset = fileOffset,
         complexAssignment);
   }
 
@@ -1546,7 +1515,7 @@
       write = new StaticSet(writeTarget, value);
     }
     complexAssignment?.write = write;
-    write.fileOffset = offsetForToken(token);
+    write.fileOffset = fileOffset;
     return write;
   }
 
@@ -1595,33 +1564,30 @@
 ///   extension B on A {
 ///     get property => 0;
 ///     set property(_) {}
-///     var field;
 ///     method() {
 ///       property;     // this generator is created for `property`.
 ///       property = 0; // this generator is created for `property`.
-///       field = 0;    // this generator is created for `field`.
 ///       method;       // this generator is created for `method`.
 ///       method();     // this generator is created for `method`.
 ///     }
 ///   }
 ///
+/// These can only occur within an extension instance member.
 class ExtensionInstanceAccessGenerator extends Generator {
   /// The static [Member] generated for an instance extension member which is
-  /// used for performing a read or invocation on this subexpression.
+  /// used for performing a read on this subexpression.
   ///
   /// This can be `null` if the subexpression doesn't have a readable target.
   /// For instance if the subexpression is a setter without a corresponding
   /// getter.
   final Procedure readTarget;
 
-  /// `true` if the [readTarget] is declared as a regular method in the
-  /// extension.
+  /// The static [Member] generated for an instance extension member which is
+  /// used for performing an invocation on this subexpression.
   ///
-  /// All extension instance members are converted into to top level methods so
-  /// this field is needed to know whether a read should be a tear off, which
-  /// is the case for regular methods, or an invocation should be a read follow
-  /// by a call, which is the case for getters.
-  final bool readTargetIsRegularMethod;
+  /// This can be `null` if the subexpression doesn't have an invokable target.
+  /// For instance if the subexpression is a getter or setter.
+  final Procedure invokeTarget;
 
   /// The static [Member] generated for an instance extension member which is
   /// used for performing a write on this subexpression.
@@ -1645,7 +1611,7 @@
       ExpressionGeneratorHelper helper,
       Token token,
       this.readTarget,
-      this.readTargetIsRegularMethod,
+      this.invokeTarget,
       this.writeTarget,
       this.extensionThis,
       this.extensionTypeParameters)
@@ -1673,23 +1639,21 @@
           offsetForToken(token),
           helper.uri);
     }
-    bool readTargetIsRegularMethod = declaration.isRegularMethod;
-    Procedure getter;
-    if (declaration.isGetter || declaration.isRegularMethod) {
-      getter = declaration.target;
+    Procedure readTarget;
+    Procedure invokeTarget;
+    if (declaration.isGetter) {
+      readTarget = declaration.target;
+    } else if (declaration.isRegularMethod) {
+      MemberBuilder procedureBuilder = declaration;
+      readTarget = procedureBuilder.extensionTearOff;
+      invokeTarget = procedureBuilder.procedure;
     }
-    Procedure setter;
+    Procedure writeTarget;
     if (builderSetter != null && builderSetter.isSetter) {
-      setter = builderSetter.target;
+      writeTarget = builderSetter.target;
     }
-    return new ExtensionInstanceAccessGenerator(
-        helper,
-        token,
-        getter,
-        readTargetIsRegularMethod,
-        setter,
-        extensionThis,
-        extensionTypeParameters);
+    return new ExtensionInstanceAccessGenerator(helper, token, readTarget,
+        invokeTarget, writeTarget, extensionThis, extensionTypeParameters);
   }
 
   @override
@@ -1698,6 +1662,20 @@
   @override
   String get _plainNameForRead => (readTarget ?? writeTarget).name.name;
 
+  int get _extensionTypeParameterCount => extensionTypeParameters?.length ?? 0;
+
+  List<DartType> _createExtensionTypeArguments() {
+    List<DartType> extensionTypeArguments = const <DartType>[];
+    if (extensionTypeParameters != null) {
+      extensionTypeArguments = [];
+      for (TypeParameter typeParameter in extensionTypeParameters) {
+        extensionTypeArguments
+            .add(_forest.createTypeParameterType(typeParameter));
+      }
+    }
+    return extensionTypeArguments;
+  }
+
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     Expression read;
@@ -1706,23 +1684,16 @@
       if (complexAssignment != null) {
         read = _helper.desugarSyntheticExpression(read);
       }
-    } else if (readTargetIsRegularMethod) {
-      read = _helper.createExtensionTearOff(
-          readTarget, extensionThis, extensionTypeParameters, token);
     } else {
-      List<DartType> typeArguments;
-      if (extensionTypeParameters != null) {
-        typeArguments = [];
-        for (TypeParameter typeParameter in extensionTypeParameters) {
-          typeArguments.add(_forest.createTypeParameterType(typeParameter));
-        }
-      }
-      read = _helper.buildStaticInvocation(
+      read = _helper.buildExtensionMethodInvocation(
+          fileOffset,
           readTarget,
-          _helper.forest.createArguments([
-            _helper.createVariableGet(extensionThis, offsetForToken(token))
-          ], token, types: typeArguments),
-          charOffset: token.charOffset);
+          _helper.forest.createArgumentsForExtensionMethod(
+              fileOffset,
+              _extensionTypeParameterCount,
+              0,
+              _helper.createVariableGet(extensionThis, fileOffset),
+              extensionTypeArguments: _createExtensionTypeArguments()));
     }
     complexAssignment?.read = read;
     return read;
@@ -1738,49 +1709,38 @@
         write = _helper.desugarSyntheticExpression(write);
       }
     } else {
-      List<DartType> typeArguments;
-      if (extensionTypeParameters != null) {
-        typeArguments = [];
-        for (TypeParameter typeParameter in extensionTypeParameters) {
-          typeArguments.add(_forest.createTypeParameterType(typeParameter));
-        }
-      }
-      write = _helper.buildStaticInvocation(
+      write = _helper.buildExtensionMethodInvocation(
+          fileOffset,
           writeTarget,
-          _helper.forest.createArguments([
-            _helper.createVariableGet(extensionThis, offsetForToken(token)),
-            value
-          ], token, types: typeArguments),
-          charOffset: token.charOffset);
+          _helper.forest.createArgumentsForExtensionMethod(
+              fileOffset,
+              _extensionTypeParameterCount,
+              0,
+              _helper.createVariableGet(extensionThis, fileOffset),
+              extensionTypeArguments: _createExtensionTypeArguments(),
+              positionalArguments: [value]));
     }
     complexAssignment?.write = write;
-    write.fileOffset = offsetForToken(token);
+    write.fileOffset = fileOffset;
     return write;
   }
 
   @override
   Expression doInvocation(int offset, Arguments arguments) {
-    if (readTargetIsRegularMethod) {
-      List<Expression> positionalArguments = [
-        _helper.createVariableGet(extensionThis, offset)
-      ]..addAll(arguments.positional);
-      List<DartType> typeArguments;
-      if (extensionTypeParameters != null) {
-        typeArguments = [];
-        for (TypeParameter typeParameter in extensionTypeParameters) {
-          typeArguments.add(_forest.createTypeParameterType(typeParameter));
-        }
-        if (arguments.types.isNotEmpty) {
-          typeArguments.addAll(arguments.types);
-        }
-      } else if (arguments.types.isNotEmpty) {
-        typeArguments = arguments.types;
-      }
-      return _helper.buildStaticInvocation(
-          readTarget,
-          _forest.createArguments(positionalArguments, token,
-              named: arguments.named, types: typeArguments),
-          charOffset: offset);
+    if (invokeTarget != null) {
+      return _helper.buildExtensionMethodInvocation(
+          offset,
+          invokeTarget,
+          _forest.createArgumentsForExtensionMethod(
+              fileOffset,
+              _extensionTypeParameterCount,
+              invokeTarget.function.typeParameters.length -
+                  _extensionTypeParameterCount,
+              _helper.createVariableGet(extensionThis, offset),
+              extensionTypeArguments: _createExtensionTypeArguments(),
+              typeArguments: arguments.types,
+              positionalArguments: arguments.positional,
+              namedArguments: arguments.named));
     } else {
       return _helper.buildMethodInvocation(buildSimpleRead(), callName,
           arguments, adjustForImplicitCall(_plainNameForRead, offset),
@@ -1802,6 +1762,298 @@
   }
 }
 
+/// A [ExplicitExtensionInstanceAccessGenerator] represents a subexpression
+/// whose prefix is a forced extension instance member access.
+///
+/// For instance
+///
+///   class A<T> {}
+///   extension B on A<int> {
+///     method() {}
+///   }
+///   extension C<T> {
+///     T get field => 0;
+///     set field(T _) {}
+///   }
+///
+///   method(A a) {
+///     B(a).method;     // this generator is created for `B(a).method`.
+///     B(a).method();   // this generator is created for `B(a).method`.
+///     C<int>(a).field; // this generator is created for `C<int>(a).field`.
+///     C(a).field = 0;  // this generator is created for `C(a).field`.
+///   }
+///
+class ExplicitExtensionInstanceAccessGenerator extends Generator {
+  /// The static [Member] generated for an instance extension member which is
+  /// used for performing a read on this subexpression.
+  ///
+  /// This can be `null` if the subexpression doesn't have a readable target.
+  /// For instance if the subexpression is a setter without a corresponding
+  /// getter.
+  final Procedure readTarget;
+
+  /// The static [Member] generated for an instance extension member which is
+  /// used for performing an invocation on this subexpression.
+  ///
+  /// This can be `null` if the subexpression doesn't have an invokable target.
+  /// For instance if the subexpression is a getter or setter.
+  final Procedure invokeTarget;
+
+  /// The static [Member] generated for an instance extension member which is
+  /// used for performing a write on this subexpression.
+  ///
+  /// This can be `null` if the subexpression doesn't have a writable target.
+  /// For instance if the subexpression is a final field, a method, or a getter
+  /// without a corresponding setter.
+  final Procedure writeTarget;
+
+  /// The expression holding the receiver value for the explicit extension
+  /// access, that is, `a` in `Extension<int>(a).method<String>()`.
+  final Expression receiver;
+
+  /// The type arguments explicitly passed to the explicit extension access,
+  /// like `<int>` in `Extension<int>(a).method<String>()`.
+  final List<DartType> explicitTypeArguments;
+
+  final int extensionTypeParameterCount;
+
+  ExplicitExtensionInstanceAccessGenerator(
+      ExpressionGeneratorHelper helper,
+      Token token,
+      this.readTarget,
+      this.invokeTarget,
+      this.writeTarget,
+      this.receiver,
+      this.explicitTypeArguments,
+      this.extensionTypeParameterCount)
+      : assert(readTarget != null || writeTarget != null),
+        assert(receiver != null),
+        super(helper, token);
+
+  factory ExplicitExtensionInstanceAccessGenerator.fromBuilder(
+      ExpressionGeneratorHelper helper,
+      Token token,
+      Builder getterBuilder,
+      Builder setterBuilder,
+      Expression receiver,
+      List<DartType> explicitTypeArguments,
+      int extensionTypeParameterCount) {
+    Procedure readTarget;
+    Procedure invokeTarget;
+    if (getterBuilder != null) {
+      if (getterBuilder is AccessErrorBuilder) {
+        AccessErrorBuilder error = getterBuilder;
+        getterBuilder = error.builder;
+        // We should only see an access error here if we've looked up a setter
+        // when not explicitly looking for a setter.
+        assert(getterBuilder.isSetter);
+      } else if (getterBuilder.isGetter) {
+        readTarget = getterBuilder.target;
+      } else if (getterBuilder.isRegularMethod) {
+        MemberBuilder procedureBuilder = getterBuilder;
+        readTarget = procedureBuilder.extensionTearOff;
+        invokeTarget = procedureBuilder.procedure;
+      } else {
+        return unhandled(
+            "${getterBuilder.runtimeType}",
+            "InstanceExtensionAccessGenerator.fromBuilder",
+            offsetForToken(token),
+            helper.uri);
+      }
+    }
+    Procedure writeTarget;
+    if (setterBuilder != null && setterBuilder.isSetter) {
+      writeTarget = setterBuilder.target;
+    }
+    return new ExplicitExtensionInstanceAccessGenerator(
+        helper,
+        token,
+        readTarget,
+        invokeTarget,
+        writeTarget,
+        receiver,
+        explicitTypeArguments,
+        extensionTypeParameterCount);
+  }
+
+  @override
+  String get _debugName => "InstanceExtensionAccessGenerator";
+
+  @override
+  String get _plainNameForRead => (readTarget ?? writeTarget).name.name;
+
+  List<DartType> _createExtensionTypeArguments() {
+    return explicitTypeArguments ?? const <DartType>[];
+  }
+
+  @override
+  Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
+    Expression read;
+    if (readTarget == null) {
+      read = _makeInvalidRead();
+      if (complexAssignment != null) {
+        read = _helper.desugarSyntheticExpression(read);
+      }
+    } else {
+      read = _helper.buildExtensionMethodInvocation(
+          fileOffset,
+          readTarget,
+          _helper.forest.createArgumentsForExtensionMethod(
+              fileOffset, extensionTypeParameterCount, 0, receiver,
+              extensionTypeArguments: _createExtensionTypeArguments()));
+    }
+    complexAssignment?.read = read;
+    return read;
+  }
+
+  @override
+  Expression _makeWrite(Expression value, bool voidContext,
+      ComplexAssignmentJudgment complexAssignment) {
+    Expression write;
+    if (writeTarget == null) {
+      write = _makeInvalidWrite(value);
+      if (complexAssignment != null) {
+        write = _helper.desugarSyntheticExpression(write);
+      }
+    } else {
+      write = _helper.buildExtensionMethodInvocation(
+          fileOffset,
+          writeTarget,
+          _helper.forest.createArgumentsForExtensionMethod(
+              fileOffset, extensionTypeParameterCount, 0, receiver,
+              extensionTypeArguments: _createExtensionTypeArguments(),
+              positionalArguments: [value]));
+    }
+    complexAssignment?.write = write;
+    write.fileOffset = fileOffset;
+    return write;
+  }
+
+  @override
+  Expression doInvocation(int offset, Arguments arguments) {
+    if (invokeTarget != null) {
+      return _helper.buildExtensionMethodInvocation(
+          fileOffset,
+          invokeTarget,
+          _forest.createArgumentsForExtensionMethod(
+              fileOffset,
+              extensionTypeParameterCount,
+              invokeTarget.function.typeParameters.length -
+                  extensionTypeParameterCount,
+              receiver,
+              extensionTypeArguments: _createExtensionTypeArguments(),
+              typeArguments: arguments.types,
+              positionalArguments: arguments.positional,
+              namedArguments: arguments.named));
+    } else {
+      return _helper.buildMethodInvocation(buildSimpleRead(), callName,
+          arguments, adjustForImplicitCall(_plainNameForRead, offset),
+          isImplicitCall: true);
+    }
+  }
+
+  @override
+  ComplexAssignmentJudgment startComplexAssignment(Expression rhs) =>
+      SyntheticWrapper.wrapStaticAssignment(rhs);
+
+  @override
+  void printOn(StringSink sink) {
+    NameSystem syntheticNames = new NameSystem();
+    sink.write(", readTarget: ");
+    printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
+    sink.write(", writeTarget: ");
+    printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
+  }
+}
+
+/// A [ExplicitExtensionAccessGenerator] represents a subexpression whose
+/// prefix is a forced extension resolution.
+///
+/// For instance
+///
+///   class A<T> {}
+///   extension B on A<int> {
+///     method() {}
+///   }
+///   extension C<T> on A<T> {
+///     T get field => 0;
+///     set field(T _) {}
+///   }
+///
+///   method(A a) {
+///     B(a).method;     // this generator is created for `B(a)`.
+///     B(a).method();   // this generator is created for `B(a)`.
+///     C<int>(a).field; // this generator is created for `C<int>(a)`.
+///     C(a).field = 0;  // this generator is created for `C(a)`.
+///   }
+///
+/// When an access is performed on this generator a
+/// [ExplicitExtensionInstanceAccessGenerator] is created.
+class ExplicitExtensionAccessGenerator extends Generator {
+  final ExtensionBuilder extensionBuilder;
+  final Expression receiver;
+  final List<DartType> explicitTypeArguments;
+
+  ExplicitExtensionAccessGenerator(
+      ExpressionGeneratorHelper helper,
+      Token token,
+      this.extensionBuilder,
+      this.receiver,
+      this.explicitTypeArguments)
+      : super(helper, token);
+
+  @override
+  String get _plainNameForRead {
+    return unsupported(
+        "ExplicitExtensionAccessGenerator.plainNameForRead", fileOffset, _uri);
+  }
+
+  @override
+  String get _debugName => "ExplicitExtensionAccessGenerator";
+
+  /* Expression | Generator */ buildPropertyAccess(
+      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+    if (_helper.constantContext != ConstantContext.none) {
+      _helper.addProblem(
+          messageNotAConstantExpression, fileOffset, token.length);
+    }
+    Builder getter = extensionBuilder.lookupLocalMember(send.name.name);
+    Builder setter =
+        extensionBuilder.lookupLocalMember(send.name.name, setter: true);
+    if (getter == null && setter == null) {
+      return new UnresolvedNameGenerator(_helper, token, send.name);
+    }
+    Generator generator =
+        new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
+            _helper,
+            token,
+            getter,
+            setter,
+            receiver,
+            explicitTypeArguments,
+            extensionBuilder.typeParameters?.length ?? 0);
+    if (send.arguments != null) {
+      return generator.doInvocation(offsetForToken(send.token), send.arguments);
+    } else {
+      return generator;
+    }
+  }
+
+  @override
+  doInvocation(int offset, Arguments arguments) {
+    return unimplemented(
+        "ExplicitExtensionAccessGenerator.doInvocation", fileOffset, _uri);
+  }
+
+  @override
+  void printOn(StringSink sink) {
+    sink.write(", extensionBuilder: ");
+    sink.write(extensionBuilder);
+    sink.write(", receiver: ");
+    sink.write(receiver);
+  }
+}
+
 class LoadLibraryGenerator extends Generator {
   final LoadLibraryBuilder builder;
 
@@ -1814,12 +2066,13 @@
 
   @override
   String get _debugName => "LoadLibraryGenerator";
+
   @override
   Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
     builder.importDependency.targetLibrary;
     LoadLibraryTearOffJudgment read = new LoadLibraryTearOffJudgment(
         builder.importDependency, builder.createTearoffMethod(_helper.forest))
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
     complexAssignment?.read = read;
     return read;
   }
@@ -1894,19 +2147,19 @@
 
   @override
   String get _plainNameForRead {
-    return unsupported(
-        "deferredAccessor.plainNameForRead", offsetForToken(token), _uri);
+    return unsupported("deferredAccessor.plainNameForRead", fileOffset, _uri);
   }
 
   @override
   String get _debugName => "DeferredAccessGenerator";
 
   @override
-  TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+  TypeBuilder buildTypeWithResolvedArguments(
+      NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
     String name = "${prefixGenerator._plainNameForRead}."
         "${suffixGenerator._plainNameForRead}";
-    TypeBuilder type =
-        suffixGenerator.buildTypeWithResolvedArguments(arguments);
+    TypeBuilder type = suffixGenerator.buildTypeWithResolvedArguments(
+        nullabilityBuilder, arguments);
     LocatedMessage message;
     if (type is NamedTypeBuilder && type.declaration is InvalidTypeBuilder) {
       InvalidTypeBuilder declaration = type.declaration;
@@ -1920,8 +2173,9 @@
           .withLocation(
               _uri, charOffset, lengthOfSpan(prefixGenerator.token, token));
     }
-    NamedTypeBuilder result = new NamedTypeBuilder(name, null);
-    _helper.library.addProblem(
+    NamedTypeBuilder result =
+        new NamedTypeBuilder(name, nullabilityBuilder, null);
+    _helper.libraryBuilder.addProblem(
         message.messageObject, message.charOffset, message.length, message.uri);
     result.bind(result.buildInvalidType(message));
     return result;
@@ -1989,10 +2243,12 @@
   String get _debugName => "TypeUseGenerator";
 
   @override
-  TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+  TypeBuilder buildTypeWithResolvedArguments(
+      NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
     if (declaration.isExtension) {
       // Extension declarations cannot be used as types.
-      return super.buildTypeWithResolvedArguments(arguments);
+      return super
+          .buildTypeWithResolvedArguments(nullabilityBuilder, arguments);
     }
     if (arguments != null) {
       int expected = declaration.typeVariablesCount;
@@ -2000,7 +2256,7 @@
         // Build the type arguments to report any errors they may have.
         _helper.buildDartTypeArguments(arguments);
         _helper.warnTypeArgumentsMismatch(
-            declaration.name, expected, offsetForToken(token));
+            declaration.name, expected, fileOffset);
         // We ignore the provided arguments, which will in turn return the
         // raw type below.
         // TODO(sigmund): change to use an InvalidType and include the raw type
@@ -2011,7 +2267,7 @@
       _helper.addProblem(
           templateMissingExplicitTypeArguments
               .withArguments(declaration.typeVariablesCount),
-          offsetForToken(token),
+          fileOffset,
           lengthForToken(token));
     }
 
@@ -2023,7 +2279,8 @@
             _helper.validateTypeUse(arguments[i], false).builder;
       }
     }
-    return new NamedTypeBuilder(_plainNameForRead, argumentBuilders)
+    return new NamedTypeBuilder(
+        _plainNameForRead, nullabilityBuilder, argumentBuilders)
       ..bind(declaration);
   }
 
@@ -2057,21 +2314,23 @@
   @override
   Expression get expression {
     if (super.expression == null) {
-      int offset = offsetForToken(token);
       if (declaration is InvalidTypeBuilder) {
         InvalidTypeBuilder declaration = this.declaration;
         _helper.addProblemErrorIfConst(
-            declaration.message.messageObject, offset, token.length);
+            declaration.message.messageObject, fileOffset, token.length);
         super.expression = _helper.wrapSyntheticExpression(
             _forest.createThrow(null,
                 _forest.createStringLiteral(declaration.message.message, token))
-              ..fileOffset = offset,
-            offset);
+              ..fileOffset = fileOffset,
+            fileOffset);
       } else {
         super.expression = _forest.createTypeLiteral(
             _helper.buildDartType(
                 new UnresolvedType(
-                    buildTypeWithResolvedArguments(null), offset, _uri),
+                    buildTypeWithResolvedArguments(
+                        const NullabilityBuilder.legacy(), null),
+                    fileOffset,
+                    _uri),
                 nonInstanceAccessIsError: true),
             token);
       }
@@ -2083,13 +2342,12 @@
   Expression _makeInvalidWrite(Expression value) {
     return _helper.wrapSyntheticExpression(
         _helper.throwNoSuchMethodError(
-            _forest.createNullLiteral(token),
+            _forest.createNullLiteral(fileOffset),
             _plainNameForRead,
-            _forest.createArguments(<Expression>[value], null)
-              ..fileOffset = value.fileOffset,
-            offsetForToken(token),
+            _forest.createArguments(fileOffset, <Expression>[value]),
+            fileOffset,
             isSetter: true),
-        offsetForToken(token));
+        fileOffset);
   }
 
   @override
@@ -2105,7 +2363,7 @@
     if (declaration is DeclarationBuilder) {
       DeclarationBuilder declaration = this.declaration;
       Builder member = declaration.findStaticBuilder(
-          name.name, offsetForToken(send.token), _uri, _helper.library);
+          name.name, offsetForToken(send.token), _uri, _helper.libraryBuilder);
 
       Generator generator;
       if (member == null) {
@@ -2132,12 +2390,12 @@
           setter = member;
         } else if (member.isGetter) {
           setter = declaration.findStaticBuilder(
-              name.name, offsetForToken(token), _uri, _helper.library,
+              name.name, fileOffset, _uri, _helper.libraryBuilder,
               isSetter: true);
         } else if (member.isField) {
           if (member.isFinal || member.isConst) {
             setter = declaration.findStaticBuilder(
-                name.name, offsetForToken(token), _uri, _helper.library,
+                name.name, fileOffset, _uri, _helper.libraryBuilder,
                 isSetter: true);
           } else {
             setter = member;
@@ -2156,9 +2414,32 @@
   }
 
   @override
-  Expression doInvocation(int offset, Arguments arguments) {
-    return _helper.buildConstructorInvocation(declaration, token, token,
-        arguments, "", null, token.charOffset, Constness.implicit);
+  doInvocation(int offset, Arguments arguments) {
+    if (declaration.isExtension) {
+      ExtensionBuilder extensionBuilder = declaration;
+      if (arguments.positional.length != 1 || arguments.named.isNotEmpty) {
+        return _helper.buildProblem(messageExplicitExtensionArgumentMismatch,
+            fileOffset, lengthForToken(token));
+      }
+      List<DartType> explicitTypeArguments =
+          getExplicitTypeArguments(arguments);
+      if (explicitTypeArguments != null) {
+        int typeParameterCount = extensionBuilder.typeParameters?.length ?? 0;
+        if (explicitTypeArguments.length != typeParameterCount) {
+          return _helper.buildProblem(
+              templateExplicitExtensionTypeArgumentMismatch.withArguments(
+                  extensionBuilder.name, typeParameterCount),
+              fileOffset,
+              lengthForToken(token));
+        }
+      }
+      // TODO(johnniwinther): Check argument and type argument count.
+      return new ExplicitExtensionAccessGenerator(_helper, token, declaration,
+          arguments.positional.single, explicitTypeArguments);
+    } else {
+      return _helper.buildConstructorInvocation(declaration, token, token,
+          arguments, "", null, token.charOffset, Constness.implicit);
+    }
   }
 }
 
@@ -2219,7 +2500,7 @@
       super._finish(makeLet(value, body), complexAssignment);
 
   @override
-  Expression doInvocation(int offset, Arguments arguments) {
+  doInvocation(int offset, Arguments arguments) {
     return _helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
         adjustForImplicitCall(_plainNameForRead, offset),
         isImplicitCall: true);
@@ -2247,7 +2528,7 @@
   Expression buildError(Arguments arguments,
       {bool isGetter: false, bool isSetter: false, int offset});
 
-  Name get name => unsupported("name", offsetForToken(token), _uri);
+  Name get name => unsupported("name", fileOffset, _uri);
 
   @override
   String get _plainNameForRead => name.name;
@@ -2257,7 +2538,7 @@
   @override
   Initializer buildFieldInitializer(Map<String, int> initializedFields) {
     return _helper.buildInvalidInitializer(_helper.desugarSyntheticExpression(
-        buildError(_forest.createArgumentsEmpty(token), isSetter: true)));
+        buildError(_forest.createArgumentsEmpty(fileOffset), isSetter: true)));
   }
 
   @override
@@ -2274,7 +2555,7 @@
 
   @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return buildError(_forest.createArguments(<Expression>[value], token),
+    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
         isSetter: true);
   }
 
@@ -2285,7 +2566,7 @@
       Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    return buildError(_forest.createArguments(<Expression>[value], token),
+    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
         isGetter: true);
   }
 
@@ -2293,9 +2574,9 @@
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
     return buildError(
-        _forest.createArguments(<Expression>[
+        _forest.createArguments(fileOffset, <Expression>[
           _forest.createIntLiteral(1, null)..fileOffset = offset
-        ], token),
+        ]),
         isGetter: true)
       ..fileOffset = offset;
   }
@@ -2304,9 +2585,9 @@
   Expression buildPostfixIncrement(Name binaryOperator,
       {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
     return buildError(
-        _forest.createArguments(<Expression>[
+        _forest.createArguments(fileOffset, <Expression>[
           _forest.createIntLiteral(1, null)..fileOffset = offset
-        ], token),
+        ]),
         isGetter: true)
       ..fileOffset = offset;
   }
@@ -2315,23 +2596,23 @@
   Expression buildNullAwareAssignment(
       Expression value, DartType type, int offset,
       {bool voidContext: false}) {
-    return buildError(_forest.createArguments(<Expression>[value], token),
+    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
         isSetter: true);
   }
 
   @override
   Expression buildSimpleRead() {
-    return buildError(_forest.createArgumentsEmpty(token), isGetter: true);
+    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
   }
 
   @override
   Expression _makeInvalidRead() {
-    return buildError(_forest.createArgumentsEmpty(token), isGetter: true);
+    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
   }
 
   @override
   Expression _makeInvalidWrite(Expression value) {
-    return buildError(_forest.createArguments(<Expression>[value], token),
+    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
         isSetter: true);
   }
 
@@ -2352,7 +2633,7 @@
         _helper.desugarSyntheticExpression(buildError(arguments)),
         null,
         arguments,
-        offsetForToken(token));
+        fileOffset);
   }
 }
 
@@ -2387,7 +2668,7 @@
   @override
   Expression buildError(Arguments arguments,
       {bool isGetter: false, bool isSetter: false, int offset}) {
-    offset ??= offsetForToken(this.token);
+    offset ??= fileOffset;
     return _helper.wrapSyntheticExpression(
         _helper.throwNoSuchMethodError(
             _forest.createNullLiteral(null)..fileOffset = offset,
@@ -2421,8 +2702,8 @@
 
   @override
   Expression buildSimpleRead() {
-    return buildError(_forest.createArgumentsEmpty(token), isGetter: true)
-      ..fileOffset = token.charOffset;
+    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
+      ..fileOffset = fileOffset;
   }
 
   @override
@@ -2435,7 +2716,7 @@
       bool isCompound, Expression value) {
     return _helper.wrapUnresolvedVariableAssignment(
         _helper.desugarSyntheticExpression(buildError(
-            _forest.createArguments(<Expression>[value], token),
+            _forest.createArguments(fileOffset, <Expression>[value]),
             isSetter: true)),
         isCompound,
         value,
@@ -2452,7 +2733,7 @@
 
   UnlinkedGenerator(
       ExpressionGeneratorHelper helper, Token token, this.declaration)
-      : name = new Name(declaration.name, helper.library.target),
+      : name = new Name(declaration.name, helper.libraryBuilder.library),
         receiver = new InvalidExpression(declaration.name)
           ..fileOffset = offsetForToken(token),
         super(helper, token);
@@ -2471,13 +2752,12 @@
 
   @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return new PropertySet(receiver, name, value)
-      ..fileOffset = offsetForToken(token);
+    return new PropertySet(receiver, name, value)..fileOffset = fileOffset;
   }
 
   @override
   Expression buildSimpleRead() {
-    return new PropertyGet(receiver, name)..fileOffset = offsetForToken(token);
+    return new PropertyGet(receiver, name)..fileOffset = fileOffset;
   }
 
   @override
@@ -2545,7 +2825,7 @@
   @override
   Expression _makeInvalidWrite(Expression value) {
     return _helper.buildProblem(messageIllegalAssignmentToNonAssignable,
-        offsetForToken(token), lengthForToken(token));
+        fileOffset, lengthForToken(token));
   }
 }
 
@@ -2574,50 +2854,50 @@
   Expression handleAssignment(bool voidContext) {
     if (_helper.constantContext != ConstantContext.none) {
       return _helper.buildProblem(
-          messageNotAConstantExpression, offsetForToken(token), token.length);
+          messageNotAConstantExpression, fileOffset, token.length);
     }
     if (identical("=", assignmentOperator)) {
       return generator.buildAssignment(value, voidContext: voidContext);
     } else if (identical("+=", assignmentOperator)) {
       return generator.buildCompoundAssignment(plusName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("-=", assignmentOperator)) {
       return generator.buildCompoundAssignment(minusName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("*=", assignmentOperator)) {
       return generator.buildCompoundAssignment(multiplyName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("%=", assignmentOperator)) {
       return generator.buildCompoundAssignment(percentName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("&=", assignmentOperator)) {
       return generator.buildCompoundAssignment(ampersandName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("/=", assignmentOperator)) {
       return generator.buildCompoundAssignment(divisionName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("<<=", assignmentOperator)) {
       return generator.buildCompoundAssignment(leftShiftName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical(">>=", assignmentOperator)) {
       return generator.buildCompoundAssignment(rightShiftName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical(">>>=", assignmentOperator)) {
       return generator.buildCompoundAssignment(tripleShiftName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("??=", assignmentOperator)) {
       return generator.buildNullAwareAssignment(
-          value, const DynamicType(), offsetForToken(token),
+          value, const DynamicType(), fileOffset,
           voidContext: voidContext);
     } else if (identical("^=", assignmentOperator)) {
       return generator.buildCompoundAssignment(caretName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("|=", assignmentOperator)) {
       return generator.buildCompoundAssignment(barName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else if (identical("~/=", assignmentOperator)) {
       return generator.buildCompoundAssignment(mustacheName, value,
-          offset: offsetForToken(token), voidContext: voidContext);
+          offset: fileOffset, voidContext: voidContext);
     } else {
       return unhandled(assignmentOperator, "handleAssignment", token.charOffset,
           _helper.uri);
@@ -2631,7 +2911,7 @@
       return generator.buildFieldInitializer(initializedFields);
     }
     return _helper.buildFieldInitializer(false, generator._plainNameForRead,
-        offsetForToken(generator.token), offsetForToken(token), value);
+        offsetForToken(generator.token), fileOffset, value);
   }
 
   @override
@@ -2658,7 +2938,7 @@
   @override
   Expression buildSimpleRead() {
     return generator.buildPostfixIncrement(binaryOperator,
-        offset: offsetForToken(token),
+        offset: fileOffset,
         voidContext: false,
         interfaceTarget: interfaceTarget);
   }
@@ -2666,7 +2946,7 @@
   @override
   Expression buildForEffect() {
     return generator.buildPostfixIncrement(binaryOperator,
-        offset: offsetForToken(token),
+        offset: fileOffset,
         voidContext: true,
         interfaceTarget: interfaceTarget);
   }
@@ -2700,7 +2980,7 @@
     if (_helper.constantContext != ConstantContext.none && prefix.deferred) {
       _helper.addProblem(
           templateCantUseDeferredPrefixAsConstant.withArguments(token),
-          offsetForToken(token),
+          fileOffset,
           lengthForToken(token));
     }
     Object result = _helper.scopeLookup(prefix.exportScope, name.lexeme, name,
@@ -2711,7 +2991,7 @@
           result = new DeferredAccessGenerator(_helper, name, this, result);
         }
       } else {
-        _helper.wrapInDeferredCheck(result, prefix, offsetForToken(token));
+        _helper.wrapInDeferredCheck(result, prefix, fileOffset);
       }
     }
     return result;
@@ -2722,9 +3002,9 @@
       int offset, Arguments arguments) {
     return _helper.wrapInLocatedProblem(
         _helper.evaluateArgumentsBefore(
-            arguments, _forest.createNullLiteral(token)),
+            arguments, _forest.createNullLiteral(fileOffset)),
         messageCantUsePrefixAsExpression.withLocation(
-            _helper.uri, offsetForToken(token), lengthForToken(token)));
+            _helper.uri, fileOffset, lengthForToken(token)));
   }
 
   @override
@@ -2735,14 +3015,13 @@
           "'${send.name.name}' != ${send.token.lexeme}");
       Object result = qualifiedLookup(send.token);
       if (send is SendAccessGenerator) {
-        result =
-            _helper.finishSend(result, send.arguments, offsetForToken(token));
+        result = _helper.finishSend(result, send.arguments, fileOffset);
       }
       if (isNullAware) {
         result = _helper.wrapInLocatedProblem(
             _helper.toValue(result),
             messageCantUsePrefixWithNullAware.withLocation(
-                _helper.uri, offsetForToken(token), lengthForToken(token)));
+                _helper.uri, fileOffset, lengthForToken(token)));
       }
       return result;
     } else {
@@ -2752,8 +3031,8 @@
 
   @override
   Expression _makeInvalidRead() {
-    return _helper.buildProblem(messageCantUsePrefixAsExpression,
-        offsetForToken(token), lengthForToken(token));
+    return _helper.buildProblem(
+        messageCantUsePrefixAsExpression, fileOffset, lengthForToken(token));
   }
 
   @override
@@ -2795,20 +3074,25 @@
             _forest.createNullLiteral(null)..fileOffset = offset,
             _plainNameForRead,
             arguments,
-            offsetForToken(token)),
-        offsetForToken(token));
+            fileOffset),
+        fileOffset);
   }
 
   @override
-  TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+  TypeBuilder buildTypeWithResolvedArguments(
+      NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
     Template<Message Function(String, String)> template = isUnresolved
         ? templateUnresolvedPrefixInTypeAnnotation
         : templateNotAPrefixInTypeAnnotation;
-    NamedTypeBuilder result = new NamedTypeBuilder(_plainNameForRead, null);
+    NamedTypeBuilder result =
+        new NamedTypeBuilder(_plainNameForRead, nullabilityBuilder, null);
     Message message =
         template.withArguments(prefixGenerator.token.lexeme, token.lexeme);
-    _helper.library.addProblem(message, offsetForToken(prefixGenerator.token),
-        lengthOfSpan(prefixGenerator.token, token), _uri);
+    _helper.libraryBuilder.addProblem(
+        message,
+        offsetForToken(prefixGenerator.token),
+        lengthOfSpan(prefixGenerator.token, token),
+        _uri);
     result.bind(result.buildInvalidType(message.withLocation(
         _uri,
         offsetForToken(prefixGenerator.token),
@@ -2840,7 +3124,7 @@
   void printOn(StringSink sink) {}
 
   Expression buildProblem() {
-    return _helper.buildProblem(message, offsetForToken(token), noLength,
+    return _helper.buildProblem(message, fileOffset, noLength,
         suppressMessage: true);
   }
 
@@ -2897,11 +3181,13 @@
     return buildProblem();
   }
 
-  TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
-    NamedTypeBuilder result = new NamedTypeBuilder(token.lexeme, null);
-    _helper.library.addProblem(message, offsetForToken(token), noLength, _uri);
-    result.bind(result.buildInvalidType(
-        message.withLocation(_uri, offsetForToken(token), noLength)));
+  TypeBuilder buildTypeWithResolvedArguments(
+      NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
+    NamedTypeBuilder result =
+        new NamedTypeBuilder(token.lexeme, nullabilityBuilder, null);
+    _helper.libraryBuilder.addProblem(message, fileOffset, noLength, _uri);
+    result.bind(result
+        .buildInvalidType(message.withLocation(_uri, fileOffset, noLength)));
     return result;
   }
 
@@ -2974,8 +3260,8 @@
       : super(helper, token);
 
   String get _plainNameForRead {
-    return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
-        offsetForToken(token), _uri);
+    return unsupported(
+        "${isSuper ? 'super' : 'this'}.plainNameForRead", fileOffset, _uri);
   }
 
   String get _debugName => "ThisAccessGenerator";
@@ -2988,8 +3274,8 @@
         return _forest.createThisExpression(token);
       }
     } else {
-      return _helper.buildProblem(messageSuperAsExpression,
-          offsetForToken(token), lengthForToken(token));
+      return _helper.buildProblem(
+          messageSuperAsExpression, fileOffset, lengthForToken(token));
     }
   }
 
@@ -2997,7 +3283,7 @@
     String keyword = isSuper ? "super" : "this";
     return _helper.buildProblem(
         templateThisOrSuperAccessInFieldInitializer.withArguments(keyword),
-        offsetForToken(token),
+        fileOffset,
         keyword.length);
   }
 
@@ -3083,7 +3369,7 @@
               ? templateSuperclassHasNoConstructor
               : templateConstructorNotFound)
           .withArguments(fullName)
-          .withLocation(_uri, offsetForToken(token), lengthForToken(token));
+          .withLocation(_uri, fileOffset, lengthForToken(token));
     }
     if (message != null) {
       return _helper.buildInvalidInitializer(_helper.wrapSyntheticExpression(
@@ -3141,7 +3427,7 @@
   Expression buildAssignmentError() {
     return _helper.desugarSyntheticExpression(_helper.buildProblem(
         isSuper ? messageCannotAssignToSuper : messageNotAnLvalue,
-        offsetForToken(token),
+        fileOffset,
         token.length));
   }
 
@@ -3183,7 +3469,7 @@
       {bool isGetter: false, bool isSetter: false, int offset}) {
     int length = noLength;
     if (offset == null) {
-      offset = offsetForToken(token);
+      offset = fileOffset;
       length = lengthForToken(token);
     }
     return _helper.buildProblem(message, offset, length);
@@ -3194,8 +3480,8 @@
 
   @override
   Expression buildSimpleRead() {
-    return buildError(_forest.createArgumentsEmpty(token), isGetter: true)
-      ..fileOffset = offsetForToken(token);
+    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
+      ..fileOffset = fileOffset;
   }
 
   @override
@@ -3224,11 +3510,11 @@
   String get _debugName => "SendAccessGenerator";
 
   Expression buildSimpleRead() {
-    return unsupported("buildSimpleRead", offsetForToken(token), _uri);
+    return unsupported("buildSimpleRead", fileOffset, _uri);
   }
 
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return unsupported("buildAssignment", offsetForToken(token), _uri);
+    return unsupported("buildAssignment", fileOffset, _uri);
   }
 
   withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
@@ -3236,7 +3522,7 @@
       return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
     }
     return _helper.buildMethodInvocation(
-        _helper.toValue(receiver), name, arguments, offsetForToken(token),
+        _helper.toValue(receiver), name, arguments, fileOffset,
         isNullAware: isNullAware);
   }
 
@@ -3252,24 +3538,21 @@
       Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    return unsupported(
-        "buildCompoundAssignment", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPrefixIncrement", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPostfixIncrement", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression doInvocation(int offset, Arguments arguments) {
@@ -3303,11 +3586,11 @@
   String get _debugName => "IncompletePropertyAccessGenerator";
 
   Expression buildSimpleRead() {
-    return unsupported("buildSimpleRead", offsetForToken(token), _uri);
+    return unsupported("buildSimpleRead", fileOffset, _uri);
   }
 
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return unsupported("buildAssignment", offsetForToken(token), _uri);
+    return unsupported("buildAssignment", fileOffset, _uri);
   }
 
   withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
@@ -3330,24 +3613,21 @@
       Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    return unsupported(
-        "buildCompoundAssignment", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPrefixIncrement", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return unsupported(
-        "buildPostfixIncrement", offset ?? offsetForToken(token), _uri);
+    return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression doInvocation(int offset, Arguments arguments) {
@@ -3371,17 +3651,17 @@
   @override
   ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
     return SyntheticWrapper.wrapIllegalAssignment(rhs,
-        assignmentOffset: offsetForToken(token));
+        assignmentOffset: fileOffset);
   }
 
   Expression _makeInvalidWrite(Expression value) {
     return _helper.wrapInvalidWrite(
         _helper.desugarSyntheticExpression(_helper.buildProblem(
             messageCannotAssignToParenthesizedExpression,
-            offsetForToken(token),
+            fileOffset,
             lengthForToken(token))),
         expression,
-        offsetForToken(token));
+        fileOffset);
   }
 }
 
@@ -3393,11 +3673,8 @@
 Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget,
     Expression right, ExpressionGeneratorHelper helper,
     {int offset: TreeNode.noOffset}) {
-  return new MethodInvocationJudgment(
-      left,
-      operator,
-      helper.forest.createArguments(<Expression>[right], null)
-        ..fileOffset = offset,
+  return new MethodInvocationJudgment(left, operator,
+      helper.forest.createArguments(offset, <Expression>[right]),
       interfaceTarget: interfaceTarget)
     ..fileOffset = offset;
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 3beeb4f..c847440 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -43,7 +43,7 @@
     show PrefixBuilder, LibraryBuilder, TypeDeclarationBuilder;
 
 abstract class ExpressionGeneratorHelper implements InferenceHelper {
-  LibraryBuilder get library;
+  LibraryBuilder get libraryBuilder;
 
   TypePromoter get typePromoter;
 
@@ -83,6 +83,9 @@
   Expression buildStaticInvocation(Procedure target, Arguments arguments,
       {Constness constness, int charOffset});
 
+  Expression buildExtensionMethodInvocation(
+      int fileOffset, Procedure target, Arguments arguments);
+
   Expression throwNoSuchMethodError(
       Expression receiver, String name, Arguments arguments, int offset,
       {Member candidate,
@@ -164,37 +167,4 @@
   /// Creates a [VariableGet] of the [variable] using [charOffset] as the file
   /// offset of the created node.
   Expression createVariableGet(VariableDeclaration variable, int charOffset);
-
-  /// Creates a tear off of the extension instance method [procedure].
-  ///
-  /// The tear off is created as a function expression that captures the
-  /// current `this` value from [extensionThis] and [extensionTypeParameters]
-  /// synthetically copied to the extension instance method.
-  ///
-  /// For instance the declaration of `B.m`:
-  ///
-  ///     class A<X, Y> {}
-  ///     class B<S, T> on A<S, T> {
-  ///       void m<U>(U u) {}
-  ///     }
-  ///
-  /// is converted into this top level method:
-  ///
-  ///     void B<S,T>|m<U>(A<S, T> #this, U u) {}
-  ///
-  /// and a tear off
-  ///
-  ///     A<X, Y> a = ...;
-  ///     var f = a.m;
-  ///
-  /// is converted into:
-  ///
-  ///     A<int, String> a = ...;
-  ///     var f = <#U>(#U u) => B<S,T>|m<int,String,#U>(a, u);
-  ///
-  Expression createExtensionTearOff(
-      Procedure procedure,
-      VariableDeclaration extensionThis,
-      List<TypeParameter> extensionTypeParameters,
-      Token token);
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 34cbd35..f63bfbc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -8,6 +8,8 @@
 
 import 'package:kernel/ast.dart';
 
+import '../names.dart';
+
 import '../parser.dart' show offsetForToken, optional;
 
 import '../problems.dart' show unsupported;
@@ -42,6 +44,7 @@
         ListLiteralJudgment,
         LoadLibraryJudgment,
         MapLiteralJudgment,
+        MethodInvocationJudgment,
         ReturnJudgment,
         SetLiteralJudgment,
         ShadowLargeIntLiteral,
@@ -58,14 +61,32 @@
 class Forest {
   const Forest();
 
-  Arguments createArguments(List<Expression> positional, Token token,
+  Arguments createArguments(int fileOffset, List<Expression> positional,
       {List<DartType> types, List<NamedExpression> named}) {
     return new ArgumentsJudgment(positional, types: types, named: named)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
   }
 
-  Arguments createArgumentsEmpty(Token token) {
-    return createArguments(<Expression>[], token);
+  Arguments createArgumentsForExtensionMethod(
+      int fileOffset,
+      int extensionTypeParameterCount,
+      int typeParameterCount,
+      Expression receiver,
+      {List<DartType> extensionTypeArguments = const <DartType>[],
+      List<DartType> typeArguments = const <DartType>[],
+      List<Expression> positionalArguments = const <Expression>[],
+      List<NamedExpression> namedArguments = const <NamedExpression>[]}) {
+    return new ArgumentsJudgment.forExtensionMethod(
+        extensionTypeParameterCount, typeParameterCount, receiver,
+        extensionTypeArguments: extensionTypeArguments,
+        typeArguments: typeArguments,
+        positionalArguments: positionalArguments,
+        namedArguments: namedArguments)
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+  }
+
+  Arguments createArgumentsEmpty(int fileOffset) {
+    return createArguments(fileOffset, <Expression>[]);
   }
 
   List<NamedExpression> argumentsNamed(Arguments arguments) {
@@ -190,9 +211,9 @@
       ..fileOffset = offsetForToken(constKeyword ?? leftBrace);
   }
 
-  /// Return a representation of a null literal at the given [location].
-  NullLiteral createNullLiteral(Token token) {
-    return new NullLiteral()..fileOffset = offsetForToken(token);
+  /// Return a representation of a null literal at the given [fileOffset].
+  NullLiteral createNullLiteral(int fileOffset) {
+    return new NullLiteral()..fileOffset = fileOffset ?? TreeNode.noOffset;
   }
 
   /// Return a representation of a simple string literal at the given
@@ -495,10 +516,10 @@
   }
 
   /// Return a representation of a return statement.
-  Statement createReturnStatement(
-      Token returnKeyword, Expression expression, int charOffset) {
-    return new ReturnJudgment(returnKeyword?.lexeme, expression)
-      ..fileOffset = charOffset;
+  Statement createReturnStatement(int fileOffset, Expression expression,
+      {bool isArrow: true}) {
+    return new ReturnJudgment(isArrow, expression)
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
   }
 
   Expression createStringConcatenation(
@@ -637,7 +658,7 @@
       bool isFieldFormal: false,
       bool isCovariant: false,
       bool isLocalFunction: false}) {
-    return VariableDeclarationJudgment(name, functionNestingLevel,
+    return new VariableDeclarationJudgment(name, functionNestingLevel,
         type: type,
         initializer: initializer,
         isFinal: isFinal,
@@ -647,6 +668,18 @@
         isLocalFunction: isLocalFunction);
   }
 
+  VariableDeclaration createVariableDeclarationForValue(
+      int fileOffset, Expression initializer,
+      {DartType type = const DynamicType()}) {
+    return new VariableDeclarationJudgment.forValue(initializer)
+      ..type = type
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+  }
+
+  Let createLet(VariableDeclaration variable, Expression body) {
+    return new Let(variable, body);
+  }
+
   FunctionNode createFunctionNode(Statement body,
       {List<TypeParameter> typeParameters,
       List<VariableDeclaration> positionalParameters,
@@ -674,13 +707,26 @@
   }
 
   FunctionExpression createFunctionExpression(
-      FunctionNode function, int fileOffset) {
-    return new FunctionExpression(function)..fileOffset = fileOffset;
+      int fileOffset, FunctionNode function) {
+    return new FunctionExpression(function)
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+  }
+
+  MethodInvocation createFunctionInvocation(
+      int fileOffset, Expression expression, Arguments arguments) {
+    return new MethodInvocationJudgment(expression, callName, arguments)
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
   }
 
   NamedExpression createNamedExpression(String name, Expression expression) {
     return new NamedExpression(name, expression);
   }
+
+  StaticInvocation createStaticInvocation(
+      int fileOffset, Procedure procedure, Arguments arguments) {
+    return new StaticInvocation(procedure, arguments)
+      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+  }
 }
 
 class _VariablesDeclaration extends Statement {
@@ -691,19 +737,19 @@
     setParents(declarations, this);
   }
 
-  accept(v) {
-    unsupported("accept", fileOffset, uri);
+  R accept<R>(v) {
+    throw unsupported("accept", fileOffset, uri);
   }
 
-  accept1(v, arg) {
-    unsupported("accept1", fileOffset, uri);
+  R accept1<R, A>(v, arg) {
+    throw unsupported("accept1", fileOffset, uri);
   }
 
   visitChildren(v) {
-    unsupported("visitChildren", fileOffset, uri);
+    throw unsupported("visitChildren", fileOffset, uri);
   }
 
   transformChildren(v) {
-    unsupported("transformChildren", fileOffset, uri);
+    throw unsupported("transformChildren", fileOffset, uri);
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index 1074242..3c7ea2e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -23,12 +23,12 @@
 
   ImplicitFieldType(this.member, this.initializerToken);
 
-  accept(DartTypeVisitor<Object> v) {
-    unsupported("accept", member.charOffset, member.fileUri);
+  R accept<R>(DartTypeVisitor<R> v) {
+    throw unsupported("accept", member.charOffset, member.fileUri);
   }
 
-  accept1(DartTypeVisitor1<Object, Object> v, arg) {
-    unsupported("accept1", member.charOffset, member.fileUri);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
+    throw unsupported("accept1", member.charOffset, member.fileUri);
   }
 
   visitChildren(Visitor<Object> v) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
index 2a35783..6cb9d18 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
@@ -21,13 +21,13 @@
   get nullability => unsupported("nullability", -1, null);
 
   @override
-  accept(DartTypeVisitor<Object> v) {
-    unhandled("$runtimeType", "${v.runtimeType}", -1, null);
+  R accept<R>(DartTypeVisitor<R> v) {
+    throw unhandled("$runtimeType", "${v.runtimeType}", -1, null);
   }
 
   @override
-  accept1(DartTypeVisitor1<Object, Object> v, arg) {
-    unhandled("$runtimeType", "${v.runtimeType}", -1, null);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
+    throw unhandled("$runtimeType", "${v.runtimeType}", -1, null);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index dcfc73d..0f0236a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -4,7 +4,8 @@
 
 part of "kernel_shadow_ast.dart";
 
-class InferenceVisitor extends BodyVisitor1<void, DartType> {
+class InferenceVisitor
+    extends BodyVisitor1<ExpressionInferenceResult, DartType> {
   final ShadowTypeInferrer inferrer;
 
   Class mapEntryClass;
@@ -24,31 +25,42 @@
   InferenceVisitor(this.inferrer);
 
   @override
-  void defaultExpression(Expression node, DartType typeContext) {
+  ExpressionInferenceResult defaultExpression(
+      Expression node, DartType typeContext) {
     unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
         inferrer.helper.uri);
+    return const ExpressionInferenceResult(const InvalidType());
   }
 
   @override
-  void defaultStatement(Statement node, _) {
+  ExpressionInferenceResult defaultStatement(Statement node, _) {
     unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
         inferrer.helper.uri);
+    return const ExpressionInferenceResult(const InvalidType());
   }
 
   @override
-  void visitInvalidExpression(InvalidExpression node, DartType typeContext) {}
+  ExpressionInferenceResult visitInvalidExpression(
+          InvalidExpression node, DartType typeContext) =>
+      const ExpressionInferenceResult(const BottomType());
 
   @override
-  void visitIntLiteral(IntLiteral node, DartType typeContext) {}
+  ExpressionInferenceResult visitIntLiteral(
+          IntLiteral node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.intClass.rawType);
 
   @override
-  void visitDoubleLiteral(DoubleLiteral node, DartType typeContext) {}
+  ExpressionInferenceResult visitDoubleLiteral(
+          DoubleLiteral node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.doubleClass.rawType);
 
   @override
-  void visitAsExpression(AsExpression node, DartType typeContext) {
+  ExpressionInferenceResult visitAsExpression(
+      AsExpression node, DartType typeContext) {
     inferrer.inferExpression(
         node.operand, const UnknownType(), !inferrer.isTopLevel,
         isVoidAllowed: true);
+    return new ExpressionInferenceResult(node.type);
   }
 
   void visitAssertInitializerJudgment(AssertInitializerJudgment node) {
@@ -73,16 +85,17 @@
   }
 
   @override
-  void visitAwaitExpression(AwaitExpression node, DartType typeContext) {
+  ExpressionInferenceResult visitAwaitExpression(
+      AwaitExpression node, DartType typeContext) {
     if (!inferrer.typeSchemaEnvironment.isEmptyContext(typeContext)) {
       typeContext = inferrer.wrapFutureOrType(typeContext);
     }
     Expression operand = node.operand;
     inferrer.inferExpression(operand, typeContext, true, isVoidAllowed: true);
-    inferrer.storeInferredType(
-        node,
-        inferrer.typeSchemaEnvironment
-            .unfutureType(getInferredType(operand, inferrer)));
+    DartType inferredType = inferrer.typeSchemaEnvironment
+        .unfutureType(getInferredType(operand, inferrer));
+    inferrer.storeInferredType(node, inferredType);
+    return new ExpressionInferenceResult(inferredType);
   }
 
   void visitBlockJudgment(BlockJudgment node) {
@@ -92,27 +105,31 @@
   }
 
   @override
-  void visitBoolLiteral(BoolLiteral node, DartType typeContext) {}
+  ExpressionInferenceResult visitBoolLiteral(
+          BoolLiteral node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.boolClass.rawType);
 
   @override
-  void visitBreakStatement(BreakStatement node, _) {
+  Null visitBreakStatement(BreakStatement node, _) {
     // No inference needs to be done.
   }
 
-  void visitCascadeJudgment(CascadeJudgment node, DartType typeContext) {
-    node.inferredType =
+  ExpressionInferenceResult visitCascadeJudgment(
+      CascadeJudgment node, DartType typeContext) {
+    ExpressionInferenceResult result =
         inferrer.inferExpression(node.targetJudgment, typeContext, true);
+    node.inferredType = result.inferredType;
     node.variable.type = getInferredType(node, inferrer);
     for (Expression judgment in node.cascadeJudgments) {
       inferrer.inferExpression(
           judgment, const UnknownType(), !inferrer.isTopLevel,
           isVoidAllowed: true);
     }
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   @override
-  void visitConditionalExpression(
+  ExpressionInferenceResult visitConditionalExpression(
       ConditionalExpression node, DartType typeContext) {
     Expression condition = node.condition;
     Expression then = node.then;
@@ -130,10 +147,11 @@
         .getStandardUpperBound(getInferredType(then, inferrer),
             getInferredType(otherwise, inferrer));
     node.staticType = inferredType;
+    return new ExpressionInferenceResult(inferredType);
   }
 
   @override
-  void visitConstructorInvocation(
+  ExpressionInferenceResult visitConstructorInvocation(
       ConstructorInvocation node, DartType typeContext) {
     LibraryBuilder library = inferrer.engine.beingInferred[node.target];
     if (library != null) {
@@ -175,14 +193,14 @@
     }
     bool hasExplicitTypeArguments =
         getExplicitTypeArguments(node.arguments) != null;
-    ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
+    DartType inferredType = inferrer.inferInvocation(
         typeContext,
         node.fileOffset,
         node.target.function.functionType,
         computeConstructorReturnType(node.target),
         node.arguments,
         isConst: node.isConst);
-    inferrer.storeInferredType(node, inferenceResult.type);
+    inferrer.storeInferredType(node, inferredType);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (!hasExplicitTypeArguments) {
@@ -191,19 +209,22 @@
             inferred: true);
       }
     }
+    return new ExpressionInferenceResult(inferredType);
   }
 
   void visitContinueSwitchJudgment(ContinueSwitchJudgment node) {
     // No inference needs to be done.
   }
-  void visitDeferredCheckJudgment(
+
+  ExpressionInferenceResult visitDeferredCheckJudgment(
       DeferredCheckJudgment node, DartType typeContext) {
     // Since the variable is not used in the body we don't need to type infer
     // it.  We can just type infer the body.
-    Expression judgment = node.judgment;
-    inferrer.inferExpression(judgment, typeContext, true, isVoidAllowed: true);
-    node.inferredType = getInferredType(judgment, inferrer);
-    return null;
+    ExpressionInferenceResult result = inferrer.inferExpression(
+        node.expression, typeContext, true,
+        isVoidAllowed: true);
+    node.inferredType = result.inferredType;
+    return new ExpressionInferenceResult(result.inferredType);
   }
 
   void visitDoJudgment(DoJudgment node) {
@@ -218,32 +239,34 @@
         node.condition.fileOffset);
   }
 
-  void visitDoubleJudgment(DoubleJudgment node, DartType typeContext) {
-    node.inferredType = inferrer.coreTypes.doubleClass.rawType;
-    return null;
+  ExpressionInferenceResult visitDoubleJudgment(
+      DoubleJudgment node, DartType typeContext) {
+    return new ExpressionInferenceResult(
+        node.inferredType = inferrer.coreTypes.doubleClass.rawType);
   }
 
   void visitEmptyStatementJudgment(EmptyStatementJudgment node) {
     // No inference needs to be done.
   }
+
   void visitExpressionStatementJudgment(ExpressionStatementJudgment node) {
     inferrer.inferExpression(
         node.judgment, const UnknownType(), !inferrer.isTopLevel,
         isVoidAllowed: true);
   }
 
-  void visitFactoryConstructorInvocationJudgment(
+  ExpressionInferenceResult visitFactoryConstructorInvocationJudgment(
       FactoryConstructorInvocationJudgment node, DartType typeContext) {
     bool hadExplicitTypeArguments =
         getExplicitTypeArguments(node.arguments) != null;
-    ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
+    DartType inferredType = inferrer.inferInvocation(
         typeContext,
         node.fileOffset,
         node.target.function.functionType,
         computeConstructorReturnType(node.target),
         node.argumentJudgments,
         isConst: node.isConst);
-    node.inferredType = inferenceResult.type;
+    node.inferredType = inferredType;
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (!hadExplicitTypeArguments) {
@@ -252,12 +275,13 @@
             inferred: true);
       }
     }
-    return null;
+    return new ExpressionInferenceResult(inferredType);
   }
 
   void visitShadowFieldInitializer(ShadowFieldInitializer node) {
-    DartType initializerType =
+    ExpressionInferenceResult initializerResult =
         inferrer.inferExpression(node.value, node.field.type, true);
+    DartType initializerType = initializerResult.inferredType;
     inferrer.ensureAssignable(
         node.field.type, initializerType, node.value, node.fileOffset);
   }
@@ -360,10 +384,10 @@
     } else if (syntheticAssignment is PropertySet ||
         syntheticAssignment is SuperPropertySet) {
       DartType receiverType = inferrer.thisType;
-      Object writeMember =
+      ObjectAccessTarget writeTarget =
           inferrer.findPropertySetMember(receiverType, syntheticAssignment);
       syntheticWriteType =
-          elementType = inferrer.getSetterType(writeMember, receiverType);
+          elementType = inferrer.getSetterType(writeTarget, receiverType);
       if (syntheticAssignment is PropertySet) {
         rhs = syntheticAssignment.value;
       } else if (syntheticAssignment is SuperPropertySet) {
@@ -403,7 +427,7 @@
   }
 
   @override
-  void visitForInStatement(ForInStatement node, _) {
+  Null visitForInStatement(ForInStatement node, _) {
     if (node.variable.name == null) {
       handleForInWithoutVariable(node.variable, node.iterable, node.body,
           isAsync: node.isAsync);
@@ -419,9 +443,10 @@
       if (variable.name == null) {
         Expression initializer = variable.initializer;
         if (initializer != null) {
-          variable.type = inferrer.inferExpression(
+          ExpressionInferenceResult result = inferrer.inferExpression(
               initializer, const UnknownType(), true,
               isVoidAllowed: true);
+          variable.type = result.inferredType;
         }
       } else {
         inferrer.inferStatement(variable);
@@ -445,7 +470,7 @@
     inferrer.inferStatement(node.body);
   }
 
-  ExpressionInferenceResult visitFunctionNodeJudgment(
+  DartType visitFunctionNodeJudgment(
       FunctionNodeJudgment node,
       DartType typeContext,
       DartType returnContext,
@@ -458,16 +483,18 @@
     inferrer.inferMetadataKeepingHelper(node.variable.annotations);
     DartType returnContext =
         node._hasImplicitReturnType ? null : node.function.returnType;
-    ExpressionInferenceResult inferenceResult = visitFunctionNodeJudgment(
+    DartType inferredType = visitFunctionNodeJudgment(
         node.functionJudgment, null, returnContext, node.fileOffset);
-    node.variable.type = inferenceResult.type;
+    node.variable.type = inferredType;
   }
 
   @override
-  void visitFunctionExpression(FunctionExpression node, DartType typeContext) {
-    ExpressionInferenceResult inferenceResult = visitFunctionNodeJudgment(
+  ExpressionInferenceResult visitFunctionExpression(
+      FunctionExpression node, DartType typeContext) {
+    DartType inferredType = visitFunctionNodeJudgment(
         node.function, typeContext, null, node.fileOffset);
-    inferrer.storeInferredType(node, inferenceResult.type);
+    inferrer.storeInferredType(node, inferredType);
+    return new ExpressionInferenceResult(inferredType);
   }
 
   void visitInvalidSuperInitializerJudgment(
@@ -485,7 +512,8 @@
         skipTypeArgumentInference: true);
   }
 
-  void visitIfNullJudgment(IfNullJudgment node, DartType typeContext) {
+  ExpressionInferenceResult visitIfNullJudgment(
+      IfNullJudgment node, DartType typeContext) {
     Expression leftJudgment = node.leftJudgment;
     Expression rightJudgment = node.rightJudgment;
     // To infer `e0 ?? e1` in context K:
@@ -509,7 +537,7 @@
     node.inferredType =
         inferrer.typeSchemaEnvironment.getStandardUpperBound(lhsType, rhsType);
     node.body.staticType = getInferredType(node, inferrer);
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   void visitIfJudgment(IfJudgment node) {
@@ -528,7 +556,7 @@
     }
   }
 
-  void visitIllegalAssignmentJudgment(
+  ExpressionInferenceResult visitIllegalAssignmentJudgment(
       IllegalAssignmentJudgment node, DartType typeContext) {
     if (node.write != null) {
       inferrer.inferExpression(
@@ -538,46 +566,49 @@
         node.rhs, const UnknownType(), !inferrer.isTopLevel);
     node._replaceWithDesugared();
     node.inferredType = const DynamicType();
-    return null;
+    return const ExpressionInferenceResult(const DynamicType());
   }
 
-  void visitIndexAssignmentJudgment(
+  ExpressionInferenceResult visitIndexAssignmentJudgment(
       IndexAssignmentJudgment node, DartType typeContext) {
     DartType receiverType = node._inferReceiver(inferrer);
-    Object writeMember =
+    ObjectAccessTarget writeTarget =
         inferrer.findMethodInvocationMember(receiverType, node.write);
     // To replicate analyzer behavior, we base type inference on the write
     // member.  TODO(paulberry): would it be better to use the read member
     // when doing compound assignment?
-    FunctionType calleeType = inferrer.getCalleeFunctionType(
-        inferrer.getCalleeType(writeMember, receiverType), false);
-    DartType expectedIndexTypeForWrite;
     DartType indexContext = const UnknownType();
-    DartType writeContext = const UnknownType();
-    if (calleeType.positionalParameters.length >= 2) {
-      // TODO(paulberry): we ought to get a context for the index expression
-      // from the index formal parameter, but analyzer doesn't so for now we
-      // replicate its behavior.
-      expectedIndexTypeForWrite = calleeType.positionalParameters[0];
-      writeContext = calleeType.positionalParameters[1];
-    }
-    inferrer.inferExpression(node.index, indexContext, true);
-    DartType indexType = getInferredType(node.index, inferrer);
+    DartType expectedIndexTypeForWrite =
+        inferrer.getIndexSetKeyType(writeTarget, receiverType);
+    DartType writeContext =
+        inferrer.getIndexSetValueType(writeTarget, receiverType);
+    ExpressionInferenceResult indexResult =
+        inferrer.inferExpression(node.index, indexContext, true);
+    DartType indexType = indexResult.inferredType;
     node._storeLetType(inferrer, node.index, indexType);
-    if (writeContext is! UnknownType) {
-      inferrer.ensureAssignable(
-          expectedIndexTypeForWrite,
-          indexType,
-          node._getInvocationArguments(inferrer, node.write).positional[0],
-          node.write.fileOffset);
+    if (indexResult.replacement != null) {
+      node.index = indexResult.replacement;
     }
+    Expression writeIndexExpression =
+        node._getInvocationArguments(inferrer, node.write).positional[0];
+    if (writeTarget.isExtensionMember) {
+      MethodInvocation write = node.write;
+      Expression replacement = inferrer.transformExtensionMethodInvocation(
+          writeTarget, write, write.receiver, write.arguments);
+      node.write = replacement;
+    }
+    if (writeContext is! UnknownType) {
+      inferrer.ensureAssignable(expectedIndexTypeForWrite, indexType,
+          writeIndexExpression, node.write.fileOffset);
+    }
+
     InvocationExpression read = node.read;
     DartType readType;
     if (read != null) {
-      Object readMember = inferrer
+      ObjectAccessTarget readMember = inferrer
           .findMethodInvocationMember(receiverType, read, instrumented: false);
-      FunctionType calleeFunctionType = inferrer.getCalleeFunctionType(
-          inferrer.getCalleeType(readMember, receiverType), false);
+      FunctionType calleeFunctionType =
+          inferrer.getFunctionType(readMember, receiverType, false);
       inferrer.ensureAssignable(
           getPositionalParameterType(calleeFunctionType, 0),
           indexType,
@@ -599,19 +630,21 @@
           read.fileOffset);
       node._storeLetType(inferrer, replacedRead, readType);
     }
-    node._inferRhs(inferrer, readType, writeContext);
+    DartType inferredType =
+        node._inferRhs(inferrer, readType, writeContext).inferredType;
     node._replaceWithDesugared();
-    return null;
+    return new ExpressionInferenceResult(inferredType);
   }
 
-  void visitIntJudgment(IntJudgment node, DartType typeContext) {
+  ExpressionInferenceResult visitIntJudgment(
+      IntJudgment node, DartType typeContext) {
     if (inferrer.isDoubleContext(typeContext)) {
       double doubleValue = node.asDouble();
       if (doubleValue != null) {
         node.parent.replaceChild(
-            node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+            node, new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
         node.inferredType = inferrer.coreTypes.doubleClass.rawType;
-        return null;
+        return new ExpressionInferenceResult(node.inferredType);
       }
     }
     Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -619,21 +652,21 @@
     if (error != null) {
       node.parent.replaceChild(node, error);
       node.inferredType = const BottomType();
-      return null;
+      return const ExpressionInferenceResult(const BottomType());
     }
     node.inferredType = inferrer.coreTypes.intClass.rawType;
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitShadowLargeIntLiteral(
+  ExpressionInferenceResult visitShadowLargeIntLiteral(
       ShadowLargeIntLiteral node, DartType typeContext) {
     if (inferrer.isDoubleContext(typeContext)) {
       double doubleValue = node.asDouble();
       if (doubleValue != null) {
         node.parent.replaceChild(
-            node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+            node, new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
         node.inferredType = inferrer.coreTypes.doubleClass.rawType;
-        return null;
+        return new ExpressionInferenceResult(node.inferredType);
       }
     }
 
@@ -646,19 +679,19 @@
               node.literal.length));
       node.parent.replaceChild(node, replacement);
       node.inferredType = const BottomType();
-      return null;
+      return const ExpressionInferenceResult(const BottomType());
     }
     Expression error = checkWebIntLiteralsErrorIfUnexact(
         inferrer, intValue, node.literal, node.fileOffset);
     if (error != null) {
       node.parent.replaceChild(node, error);
       node.inferredType = const BottomType();
-      return null;
+      return const ExpressionInferenceResult(const BottomType());
     }
-    node.parent
-        .replaceChild(node, IntLiteral(intValue)..fileOffset = node.fileOffset);
+    node.parent.replaceChild(
+        node, new IntLiteral(intValue)..fileOffset = node.fileOffset);
     node.inferredType = inferrer.coreTypes.intClass.rawType;
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   void visitShadowInvalidInitializer(ShadowInvalidInitializer node) {
@@ -671,13 +704,15 @@
   }
 
   @override
-  void visitIsExpression(IsExpression node, DartType typeContext) {
+  ExpressionInferenceResult visitIsExpression(
+      IsExpression node, DartType typeContext) {
     inferrer.inferExpression(
         node.operand, const UnknownType(), !inferrer.isTopLevel);
+    return new ExpressionInferenceResult(inferrer.coreTypes.boolClass.rawType);
   }
 
   @override
-  void visitLabeledStatement(LabeledStatement node, _) {
+  Null visitLabeledStatement(LabeledStatement node, _) {
     inferrer.inferStatement(node.body);
   }
 
@@ -703,12 +738,13 @@
       bool inferenceNeeded,
       bool typeChecksNeeded) {
     if (element is SpreadElement) {
-      DartType spreadType = inferrer.inferExpression(
+      ExpressionInferenceResult spreadResult = inferrer.inferExpression(
           element.expression,
           new InterfaceType(inferrer.coreTypes.iterableClass,
               <DartType>[inferredTypeArgument]),
           inferenceNeeded || typeChecksNeeded,
           isVoidAllowed: true);
+      DartType spreadType = spreadResult.inferredType;
       inferredSpreadTypes[element.expression] = spreadType;
       if (typeChecksNeeded) {
         DartType spreadElementType =
@@ -750,9 +786,10 @@
               const DynamicType();
     } else if (element is IfElement) {
       DartType boolType = inferrer.coreTypes.boolClass.rawType;
-      DartType conditionType = inferrer.inferExpression(
+      ExpressionInferenceResult conditionResult = inferrer.inferExpression(
           element.condition, boolType, typeChecksNeeded,
           isVoidAllowed: false);
+      DartType conditionType = conditionResult.inferredType;
       inferrer.ensureAssignable(boolType, conditionType, element.condition,
           element.condition.fileOffset);
       DartType thenType = inferElement(
@@ -780,9 +817,11 @@
       for (VariableDeclaration declaration in element.variables) {
         if (declaration.name == null) {
           if (declaration.initializer != null) {
-            declaration.type = inferrer.inferExpression(declaration.initializer,
-                declaration.type, inferenceNeeded || typeChecksNeeded,
-                isVoidAllowed: true);
+            ExpressionInferenceResult initializerResult =
+                inferrer.inferExpression(declaration.initializer,
+                    declaration.type, inferenceNeeded || typeChecksNeeded,
+                    isVoidAllowed: true);
+            declaration.type = initializerResult.inferredType;
           }
         } else {
           inferrer.inferStatement(declaration);
@@ -820,9 +859,10 @@
       return inferElement(element.body, element, inferredTypeArgument,
           inferredSpreadTypes, inferenceNeeded, typeChecksNeeded);
     } else {
-      DartType inferredType = inferrer.inferExpression(
+      ExpressionInferenceResult result = inferrer.inferExpression(
           element, inferredTypeArgument, inferenceNeeded || typeChecksNeeded,
           isVoidAllowed: true);
+      DartType inferredType = result.inferredType;
       if (inferredTypeArgument is! UnknownType) {
         inferrer.ensureAssignable(
             inferredTypeArgument, inferredType, element, element.fileOffset,
@@ -859,7 +899,7 @@
     }
   }
 
-  void visitListLiteralJudgment(
+  ExpressionInferenceResult visitListLiteralJudgment(
       ListLiteralJudgment node, DartType typeContext) {
     Class listClass = inferrer.coreTypes.listClass;
     InterfaceType listType = listClass.thisType;
@@ -931,11 +971,12 @@
       }
     }
 
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   @override
-  void visitLogicalExpression(LogicalExpression node, DartType typeContext) {
+  ExpressionInferenceResult visitLogicalExpression(
+      LogicalExpression node, DartType typeContext) {
     InterfaceType boolType = inferrer.coreTypes.boolClass.rawType;
     Expression left = node.left;
     Expression right = node.right;
@@ -945,7 +986,7 @@
         node.left, node.left.fileOffset);
     inferrer.ensureAssignable(boolType, getInferredType(right, inferrer),
         node.right, node.right.fileOffset);
-    return null;
+    return new ExpressionInferenceResult(boolType);
   }
 
   // Calculates the key and the value type of a spread map entry of type
@@ -987,9 +1028,10 @@
       bool inferenceNeeded,
       bool typeChecksNeeded) {
     if (entry is SpreadMapEntry) {
-      DartType spreadType = inferrer.inferExpression(
+      ExpressionInferenceResult spreadResult = inferrer.inferExpression(
           entry.expression, spreadContext, inferenceNeeded || typeChecksNeeded,
           isVoidAllowed: true);
+      DartType spreadType = spreadResult.inferredType;
       inferredSpreadTypes[entry.expression] = spreadType;
       int length = actualTypes.length;
       actualTypes.add(null);
@@ -1090,9 +1132,10 @@
       return;
     } else if (entry is IfMapEntry) {
       DartType boolType = inferrer.coreTypes.boolClass.rawType;
-      DartType conditionType = inferrer.inferExpression(
+      ExpressionInferenceResult conditionResult = inferrer.inferExpression(
           entry.condition, boolType, typeChecksNeeded,
           isVoidAllowed: false);
+      DartType conditionType = conditionResult.inferredType;
       inferrer.ensureAssignable(
           boolType, conditionType, entry.condition, entry.condition.fileOffset);
       // Note that this recursive invocation of inferMapEntry will add two types
@@ -1141,9 +1184,12 @@
       for (VariableDeclaration declaration in entry.variables) {
         if (declaration.name == null) {
           if (declaration.initializer != null) {
-            declaration.type = inferrer.inferExpression(declaration.initializer,
-                declaration.type, inferenceNeeded || typeChecksNeeded,
+            ExpressionInferenceResult result = inferrer.inferExpression(
+                declaration.initializer,
+                declaration.type,
+                inferenceNeeded || typeChecksNeeded,
                 isVoidAllowed: true);
+            declaration.type = result.inferredType;
           }
         } else {
           inferrer.inferStatement(declaration);
@@ -1201,12 +1247,14 @@
           inferenceNeeded,
           typeChecksNeeded);
     } else {
-      DartType keyType = inferrer.inferExpression(
+      ExpressionInferenceResult keyResult = inferrer.inferExpression(
           entry.key, inferredKeyType, true,
           isVoidAllowed: true);
-      DartType valueType = inferrer.inferExpression(
+      DartType keyType = keyResult.inferredType;
+      ExpressionInferenceResult valueResult = inferrer.inferExpression(
           entry.value, inferredValueType, true,
           isVoidAllowed: true);
+      DartType valueType = valueResult.inferredType;
       inferrer.ensureAssignable(
           inferredKeyType, keyType, entry.key, entry.key.fileOffset,
           isVoidAllowed: inferredKeyType is VoidType);
@@ -1272,7 +1320,8 @@
     }
   }
 
-  void visitMapLiteralJudgment(MapLiteralJudgment node, DartType typeContext) {
+  ExpressionInferenceResult visitMapLiteralJudgment(
+      MapLiteralJudgment node, DartType typeContext) {
     Class mapClass = inferrer.coreTypes.mapClass;
     InterfaceType mapType = mapClass.thisType;
     List<DartType> inferredTypes;
@@ -1307,7 +1356,7 @@
           node.parent.replaceChild(node, setLiteral);
           visitSetLiteralJudgment(setLiteral, typeContext);
           node.inferredType = setLiteral.inferredType;
-          return;
+          return new ExpressionInferenceResult(node.inferredType);
         }
       }
     }
@@ -1425,7 +1474,7 @@
 
         node.inferredType = setLiteral.inferredType =
             new InterfaceType(inferrer.coreTypes.setClass, inferredTypesForSet);
-        return;
+        return new ExpressionInferenceResult(node.inferredType);
       }
       if (canBeSet && canBeMap && node.entries.isNotEmpty) {
         node.parent.replaceChild(
@@ -1434,7 +1483,7 @@
                 .buildProblem(messageCantDisambiguateNotEnoughInformation,
                     node.fileOffset, 1)));
         node.inferredType = const BottomType();
-        return;
+        return const ExpressionInferenceResult(const BottomType());
       }
       if (!canBeSet && !canBeMap) {
         if (!inferrer.isTopLevel) {
@@ -1445,7 +1494,7 @@
                       node.fileOffset, 1)));
         }
         node.inferredType = const BottomType();
-        return;
+        return const ExpressionInferenceResult(const BottomType());
       }
       inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
           mapType,
@@ -1483,9 +1532,10 @@
             inferred: true);
       }
     }
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitMethodInvocationJudgment(
+  ExpressionInferenceResult visitMethodInvocationJudgment(
       MethodInvocationJudgment node, DartType typeContext) {
     if (node.name.name == 'unary-' &&
         node.arguments.types.isEmpty &&
@@ -1505,10 +1555,10 @@
         if (inferrer.isDoubleContext(typeContext)) {
           double doubleValue = receiver.asDouble(negated: true);
           if (doubleValue != null) {
-            node.parent.replaceChild(
-                node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+            node.parent.replaceChild(node,
+                new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
             node.inferredType = inferrer.coreTypes.doubleClass.rawType;
-            return null;
+            return new ExpressionInferenceResult(node.inferredType);
           }
         }
         Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -1516,7 +1566,7 @@
         if (error != null) {
           node.parent.replaceChild(node, error);
           node.inferredType = const BottomType();
-          return null;
+          return const ExpressionInferenceResult(const BottomType());
         }
       } else if (node.receiver is ShadowLargeIntLiteral) {
         ShadowLargeIntLiteral receiver = node.receiver;
@@ -1525,9 +1575,9 @@
             double doubleValue = receiver.asDouble(negated: true);
             if (doubleValue != null) {
               node.parent.replaceChild(node,
-                  DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+                  new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
               node.inferredType = inferrer.coreTypes.doubleClass.rawType;
-              return null;
+              return new ExpressionInferenceResult(node.inferredType);
             }
           }
           int intValue = receiver.asInt64(negated: true);
@@ -1540,7 +1590,7 @@
                     receiver.literal.length));
             node.parent.replaceChild(node, error);
             node.inferredType = const BottomType();
-            return null;
+            return const ExpressionInferenceResult(const BottomType());
           }
           if (intValue != null) {
             Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -1548,64 +1598,69 @@
             if (error != null) {
               node.parent.replaceChild(node, error);
               node.inferredType = const BottomType();
-              return null;
+              return const ExpressionInferenceResult(const BottomType());
             }
-            node.receiver = IntLiteral(-intValue)
+            node.receiver = new IntLiteral(-intValue)
               ..fileOffset = node.receiver.fileOffset
               ..parent = node;
           }
         }
       }
     }
-    ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+    ExpressionInferenceResult result = inferrer.inferMethodInvocation(
         node, node.receiver, node.fileOffset, node._isImplicitCall, typeContext,
         desugaredInvocation: node);
-    node.inferredType = inferenceResult.type;
+    node.inferredType = result.inferredType;
+    return new ExpressionInferenceResult(
+        result.inferredType, result.replacement);
   }
 
-  void visitNamedFunctionExpressionJudgment(
+  ExpressionInferenceResult visitNamedFunctionExpressionJudgment(
       NamedFunctionExpressionJudgment node, DartType typeContext) {
     Expression initializer = node.variableJudgment.initializer;
     inferrer.inferExpression(initializer, typeContext, true);
     node.inferredType = getInferredType(initializer, inferrer);
     node.variable.type = node.inferredType;
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   @override
-  void visitNot(Not node, DartType typeContext) {
+  ExpressionInferenceResult visitNot(Not node, DartType typeContext) {
     Expression operand = node.operand;
     InterfaceType boolType = inferrer.coreTypes.boolClass.rawType;
     inferrer.inferExpression(operand, boolType, !inferrer.isTopLevel);
     inferrer.ensureAssignable(boolType, getInferredType(operand, inferrer),
         node.operand, node.fileOffset);
+    return new ExpressionInferenceResult(boolType);
   }
 
-  void visitNullAwareMethodInvocationJudgment(
+  ExpressionInferenceResult visitNullAwareMethodInvocationJudgment(
       NullAwareMethodInvocationJudgment node, DartType typeContext) {
-    ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+    ExpressionInferenceResult result = inferrer.inferMethodInvocation(
         node, node.variable.initializer, node.fileOffset, false, typeContext,
         receiverVariable: node.variable,
         desugaredInvocation: node._desugaredInvocation);
-    node.inferredType = inferenceResult.type;
+    node.inferredType = result.inferredType;
     node.body.staticType = node.inferredType;
-    return null;
+    return new ExpressionInferenceResult(result.inferredType);
   }
 
-  void visitNullAwarePropertyGetJudgment(
+  ExpressionInferenceResult visitNullAwarePropertyGetJudgment(
       NullAwarePropertyGetJudgment node, DartType typeContext) {
-    inferrer.inferPropertyGet(
+    ExpressionInferenceResult result = inferrer.inferPropertyGet(
         node, node.receiverJudgment, node.fileOffset, typeContext,
         receiverVariable: node.variable, desugaredGet: node._desugaredGet);
-    node.body.staticType = node.inferredType;
-    return null;
+    node.body.staticType = result.inferredType;
+    return new ExpressionInferenceResult(result.inferredType);
   }
 
   @override
-  void visitNullLiteral(NullLiteral node, DartType typeContext) {}
+  ExpressionInferenceResult visitNullLiteral(
+          NullLiteral node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.nullClass.rawType);
 
   @override
-  void visitLet(Let node, DartType typeContext) {
+  ExpressionInferenceResult visitLet(Let node, DartType typeContext) {
     DartType variableType = node.variable.type;
     if (variableType == const DynamicType()) {
       return defaultExpression(node, typeContext);
@@ -1614,47 +1669,72 @@
     inferrer.inferExpression(initializer, variableType, true,
         isVoidAllowed: true);
     Expression body = node.body;
-    inferrer.inferExpression(body, typeContext, true, isVoidAllowed: true);
+    ExpressionInferenceResult result =
+        inferrer.inferExpression(body, typeContext, true, isVoidAllowed: true);
+    DartType inferredType = result.inferredType;
     // TODO(ahe): This shouldn't be needed. See InferredTypeVisitor.visitLet.
-    inferrer.storeInferredType(node, getInferredType(body, inferrer));
+    inferrer.storeInferredType(node, inferredType);
+    return new ExpressionInferenceResult(inferredType);
   }
 
-  void visitPropertyAssignmentJudgment(
+  ExpressionInferenceResult visitPropertyAssignmentJudgment(
       PropertyAssignmentJudgment node, DartType typeContext) {
     DartType receiverType = node._inferReceiver(inferrer);
 
     DartType readType;
     if (node.read != null) {
-      Object readMember = inferrer
+      ObjectAccessTarget readTarget = inferrer
           .findPropertyGetMember(receiverType, node.read, instrumented: false);
-      readType = inferrer.getCalleeType(readMember, receiverType);
+      readType = inferrer.getGetterType(readTarget, receiverType);
       inferrer.handlePropertyGetContravariance(
           node.receiver,
-          readMember,
+          readTarget,
           node.read is PropertyGet ? node.read : null,
           node.read,
           readType,
           node.read.fileOffset);
       node._storeLetType(inferrer, node.read, readType);
     }
-    Member writeMember;
+    ObjectAccessTarget writeTarget;
     if (node.write != null) {
-      writeMember = node._handleWriteContravariance(inferrer, receiverType);
+      writeTarget = node._handleWriteContravariance(inferrer, receiverType);
     }
     // To replicate analyzer behavior, we base type inference on the write
     // member.  TODO(paulberry): would it be better to use the read member when
     // doing compound assignment?
-    DartType writeContext = inferrer.getSetterType(writeMember, receiverType);
-    node._inferRhs(inferrer, readType, writeContext);
+    DartType writeContext = inferrer.getSetterType(writeTarget, receiverType);
+    DartType inferredType =
+        node._inferRhs(inferrer, readType, writeContext).inferredType;
     node.nullAwareGuard?.staticType = node.inferredType;
-    node._replaceWithDesugared();
-    return null;
+    Expression replacement;
+    if (writeTarget.isExtensionMember) {
+      node.parent.replaceChild(
+          node,
+          replacement = inferrer.helper.forest.createStaticInvocation(
+              node.fileOffset,
+              writeTarget.member,
+              inferrer.helper.forest.createArgumentsForExtensionMethod(
+                  node.fileOffset,
+                  writeTarget.inferredExtensionTypeArguments.length,
+                  0,
+                  node.receiver,
+                  extensionTypeArguments:
+                      writeTarget.inferredExtensionTypeArguments,
+                  positionalArguments: [node.rhs])));
+      inferrer.storeInferredType(replacement, inferredType);
+    } else {
+      node._replaceWithDesugared();
+    }
+
+    return new ExpressionInferenceResult(inferredType, replacement);
   }
 
   @override
-  void visitPropertyGet(PropertyGet node, DartType typeContext) {
-    inferrer.inferPropertyGet(node, node.receiver, node.fileOffset, typeContext,
-        desugaredGet: node);
+  ExpressionInferenceResult visitPropertyGet(
+      PropertyGet node, DartType typeContext) {
+    return inferrer.inferPropertyGet(
+        node, node.receiver, node.fileOffset, typeContext,
+        desugaredGet: node, allowExtensionMethods: true);
   }
 
   void visitRedirectingInitializerJudgment(
@@ -1679,7 +1759,8 @@
   }
 
   @override
-  void visitRethrow(Rethrow node, DartType typeContext) {}
+  ExpressionInferenceResult visitRethrow(Rethrow node, DartType typeContext) =>
+      const ExpressionInferenceResult(const BottomType());
 
   void visitReturnJudgment(ReturnJudgment node) {
     Expression judgment = node.judgment;
@@ -1695,11 +1776,11 @@
     } else {
       inferredType = inferrer.coreTypes.nullClass.rawType;
     }
-    closureContext.handleReturn(inferrer, node, inferredType,
-        !identical(node.returnKeywordLexeme, "return"));
+    closureContext.handleReturn(inferrer, node, inferredType, node.isArrow);
   }
 
-  void visitSetLiteralJudgment(SetLiteralJudgment node, DartType typeContext) {
+  ExpressionInferenceResult visitSetLiteralJudgment(
+      SetLiteralJudgment node, DartType typeContext) {
     Class setClass = inferrer.coreTypes.setClass;
     InterfaceType setType = setClass.thisType;
     List<DartType> inferredTypes;
@@ -1773,9 +1854,10 @@
         inferrer.helper.transformSetLiterals = true;
       }
     }
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitStaticAssignmentJudgment(
+  ExpressionInferenceResult visitStaticAssignmentJudgment(
       StaticAssignmentJudgment node, DartType typeContext) {
     DartType readType = const DynamicType(); // Only used in error recovery
     Expression read = node.read;
@@ -1791,13 +1873,15 @@
       writeMember = write.target;
       TypeInferenceEngine.resolveInferenceNode(writeMember);
     }
-    node._inferRhs(inferrer, readType, writeContext);
+    DartType inferredType =
+        node._inferRhs(inferrer, readType, writeContext).inferredType;
     node._replaceWithDesugared();
-    return null;
+    return new ExpressionInferenceResult(inferredType);
   }
 
   @override
-  void visitStaticGet(StaticGet node, DartType typeContext) {
+  ExpressionInferenceResult visitStaticGet(
+      StaticGet node, DartType typeContext) {
     Member target = node.target;
     TypeInferenceEngine.resolveInferenceNode(target);
     DartType type = target.getterType;
@@ -1805,31 +1889,32 @@
       type = inferrer.instantiateTearOff(type, typeContext, node);
     }
     inferrer.storeInferredType(node, type);
+    return new ExpressionInferenceResult(type);
   }
 
   @override
-  void visitStaticInvocation(StaticInvocation node, DartType typeContext) {
+  ExpressionInferenceResult visitStaticInvocation(
+      StaticInvocation node, DartType typeContext) {
     FunctionType calleeType = node.target != null
         ? node.target.function.functionType
         : new FunctionType([], const DynamicType());
     bool hadExplicitTypeArguments =
         getExplicitTypeArguments(node.arguments) != null;
-    ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
-        typeContext,
-        node.fileOffset,
-        calleeType,
-        calleeType.returnType,
-        node.arguments);
-    inferrer.storeInferredType(node, inferenceResult.type);
-    if (!hadExplicitTypeArguments && node.target != null) {
-      inferrer.library?.checkBoundsInStaticInvocation(
+    DartType inferredType = inferrer.inferInvocation(typeContext,
+        node.fileOffset, calleeType, calleeType.returnType, node.arguments);
+    inferrer.storeInferredType(node, inferredType);
+    if (!inferrer.isTopLevel &&
+        !hadExplicitTypeArguments &&
+        node.target != null) {
+      inferrer.library.checkBoundsInStaticInvocation(
           node, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
           inferred: true);
     }
+    return new ExpressionInferenceResult(inferredType);
   }
 
   @override
-  void visitStringConcatenation(
+  ExpressionInferenceResult visitStringConcatenation(
       StringConcatenation node, DartType typeContext) {
     if (!inferrer.isTopLevel) {
       for (Expression expression in node.expressions) {
@@ -1837,10 +1922,14 @@
             expression, const UnknownType(), !inferrer.isTopLevel);
       }
     }
+    return new ExpressionInferenceResult(
+        inferrer.coreTypes.stringClass.rawType);
   }
 
   @override
-  void visitStringLiteral(StringLiteral node, DartType typeContext) {}
+  ExpressionInferenceResult visitStringLiteral(
+          StringLiteral node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.stringClass.rawType);
 
   void visitSuperInitializerJudgment(SuperInitializerJudgment node) {
     Substitution substitution = Substitution.fromSupertype(
@@ -1856,28 +1945,34 @@
         skipTypeArgumentInference: true);
   }
 
-  void visitSuperMethodInvocationJudgment(
+  ExpressionInferenceResult visitSuperMethodInvocationJudgment(
       SuperMethodInvocationJudgment node, DartType typeContext) {
     if (node.interfaceTarget != null) {
       inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
           new InstrumentationValueForMember(node.interfaceTarget));
     }
-    ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+    ExpressionInferenceResult result = inferrer.inferMethodInvocation(
         node, null, node.fileOffset, false, typeContext,
-        interfaceMember: node.interfaceTarget,
+        target: node.interfaceTarget != null
+            ? new ObjectAccessTarget.interfaceMember(node.interfaceTarget)
+            : const ObjectAccessTarget.unresolved(),
         methodName: node.name,
         arguments: node.arguments);
-    node.inferredType = inferenceResult.type;
+    node.inferredType = result.inferredType;
+    return new ExpressionInferenceResult(result.inferredType);
   }
 
-  void visitSuperPropertyGetJudgment(
+  ExpressionInferenceResult visitSuperPropertyGetJudgment(
       SuperPropertyGetJudgment node, DartType typeContext) {
     if (node.interfaceTarget != null) {
       inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
           new InstrumentationValueForMember(node.interfaceTarget));
     }
-    inferrer.inferPropertyGet(node, null, node.fileOffset, typeContext,
-        interfaceMember: node.interfaceTarget, propertyName: node.name);
+    return inferrer.inferPropertyGet(node, null, node.fileOffset, typeContext,
+        readTarget: node.interfaceTarget != null
+            ? new ObjectAccessTarget.interfaceMember(node.interfaceTarget)
+            : const ObjectAccessTarget.unresolved(),
+        propertyName: node.name);
   }
 
   void visitSwitchStatementJudgment(SwitchStatementJudgment node) {
@@ -1887,8 +1982,9 @@
 
     for (SwitchCaseJudgment switchCase in node.caseJudgments) {
       for (Expression caseExpression in switchCase.expressionJudgments) {
-        DartType caseExpressionType =
+        ExpressionInferenceResult caseExpressionResult =
             inferrer.inferExpression(caseExpression, expressionType, true);
+        DartType caseExpressionType = caseExpressionResult.inferredType;
 
         // Check whether the expression type is assignable to the case
         // expression type.
@@ -1908,13 +2004,13 @@
     }
   }
 
-  void visitSymbolLiteralJudgment(
+  ExpressionInferenceResult visitSymbolLiteralJudgment(
       SymbolLiteralJudgment node, DartType typeContext) {
     node.inferredType = inferrer.coreTypes.symbolClass.rawType;
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitInvalidConstructorInvocationJudgment(
+  ExpressionInferenceResult visitInvalidConstructorInvocationJudgment(
       InvalidConstructorInvocationJudgment node, DartType typeContext) {
     FunctionType calleeType;
     DartType returnType;
@@ -1925,17 +2021,13 @@
       calleeType = new FunctionType([], const DynamicType());
       returnType = const DynamicType();
     }
-    ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
-        typeContext,
-        node.fileOffset,
-        calleeType,
-        returnType,
-        node.argumentJudgments);
-    node.inferredType = inferenceResult.type;
+    DartType inferredType = inferrer.inferInvocation(typeContext,
+        node.fileOffset, calleeType, returnType, node.argumentJudgments);
+    node.inferredType = inferredType;
     return visitSyntheticExpressionJudgment(node, typeContext);
   }
 
-  void visitInvalidWriteJudgment(
+  ExpressionInferenceResult visitInvalidWriteJudgment(
       InvalidWriteJudgment node, DartType typeContext) {
     // When a compound assignment, the expression is already wrapping in
     // VariableDeclaration in _makeRead(). Otherwise, temporary associate
@@ -1947,19 +2039,22 @@
     return visitSyntheticExpressionJudgment(node, typeContext);
   }
 
-  void visitSyntheticExpressionJudgment(
+  ExpressionInferenceResult visitSyntheticExpressionJudgment(
       SyntheticExpressionJudgment node, DartType typeContext) {
     node._replaceWithDesugared();
     node.inferredType = const DynamicType();
-    return null;
+    return const ExpressionInferenceResult(const DynamicType());
   }
 
-  void visitThisExpression(ThisExpression node, DartType typeContext) {}
+  ExpressionInferenceResult visitThisExpression(
+          ThisExpression node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.thisType);
 
   @override
-  void visitThrow(Throw node, DartType typeContext) {
+  ExpressionInferenceResult visitThrow(Throw node, DartType typeContext) {
     inferrer.inferExpression(
         node.expression, const UnknownType(), !inferrer.isTopLevel);
+    return const ExpressionInferenceResult(const BottomType());
   }
 
   void visitCatchJudgment(CatchJudgment node) {
@@ -1978,13 +2073,13 @@
     inferrer.inferStatement(node.finalizer);
   }
 
-  void visitTypeLiteralJudgment(
+  ExpressionInferenceResult visitTypeLiteralJudgment(
       TypeLiteralJudgment node, DartType typeContext) {
     node.inferredType = inferrer.coreTypes.typeClass.rawType;
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitVariableAssignmentJudgment(
+  ExpressionInferenceResult visitVariableAssignmentJudgment(
       VariableAssignmentJudgment node, DartType typeContext) {
     DartType readType;
     Expression read = node.read;
@@ -1999,9 +2094,10 @@
         node._storeLetType(inferrer, read, writeContext);
       }
     }
-    node._inferRhs(inferrer, readType, writeContext);
+    DartType inferredType =
+        node._inferRhs(inferrer, readType, writeContext).inferredType;
     node._replaceWithDesugared();
-    return null;
+    return new ExpressionInferenceResult(inferredType);
   }
 
   void visitVariableDeclarationJudgment(VariableDeclarationJudgment node) {
@@ -2011,10 +2107,12 @@
     DartType inferredType;
     DartType initializerType;
     if (initializerJudgment != null) {
-      inferrer.inferExpression(initializerJudgment, declaredType,
+      ExpressionInferenceResult initializerResult = inferrer.inferExpression(
+          initializerJudgment,
+          declaredType,
           !inferrer.isTopLevel || node._implicitlyTyped,
           isVoidAllowed: true);
-      initializerType = getInferredType(initializerJudgment, inferrer);
+      initializerType = initializerResult.inferredType;
       inferredType = inferrer.inferDeclarationType(initializerType);
     } else {
       inferredType = const DynamicType();
@@ -2042,9 +2140,10 @@
     }
   }
 
-  void visitUnresolvedTargetInvocationJudgment(
+  ExpressionInferenceResult visitUnresolvedTargetInvocationJudgment(
       UnresolvedTargetInvocationJudgment node, DartType typeContext) {
-    void result = visitSyntheticExpressionJudgment(node, typeContext);
+    ExpressionInferenceResult result =
+        visitSyntheticExpressionJudgment(node, typeContext);
     inferrer.inferInvocation(
         typeContext,
         node.fileOffset,
@@ -2054,7 +2153,7 @@
     return result;
   }
 
-  void visitUnresolvedVariableAssignmentJudgment(
+  ExpressionInferenceResult visitUnresolvedVariableAssignmentJudgment(
       UnresolvedVariableAssignmentJudgment node, DartType typeContext) {
     inferrer.inferExpression(node.rhs, const UnknownType(), true);
     node.inferredType = node.isCompound
@@ -2063,7 +2162,7 @@
     return visitSyntheticExpressionJudgment(node, typeContext);
   }
 
-  void visitVariableGetJudgment(
+  ExpressionInferenceResult visitVariableGetJudgment(
       VariableGetJudgment node, DartType typeContext) {
     VariableDeclarationJudgment variable = node.variable;
     bool mutatedInClosure = variable._mutatedInClosure;
@@ -2081,7 +2180,7 @@
       type = inferrer.instantiateTearOff(type, typeContext, node);
     }
     node.inferredType = type;
-    return null;
+    return new ExpressionInferenceResult(type);
   }
 
   void visitWhileJudgment(WhileJudgment node) {
@@ -2117,7 +2216,7 @@
         getInferredType(judgment, inferrer), node.expression, node.fileOffset);
   }
 
-  void visitLoadLibraryJudgment(
+  ExpressionInferenceResult visitLoadLibraryJudgment(
       LoadLibraryJudgment node, DartType typeContext) {
     node.inferredType =
         inferrer.typeSchemaEnvironment.futureType(const DynamicType());
@@ -2126,17 +2225,18 @@
       inferrer.inferInvocation(typeContext, node.fileOffset, calleeType,
           calleeType.returnType, node.argumentJudgments);
     }
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
-  void visitLoadLibraryTearOffJudgment(
+  ExpressionInferenceResult visitLoadLibraryTearOffJudgment(
       LoadLibraryTearOffJudgment node, DartType typeContext) {
     node.inferredType = new FunctionType(
         [], inferrer.typeSchemaEnvironment.futureType(const DynamicType()));
-    return null;
+    return new ExpressionInferenceResult(node.inferredType);
   }
 
   @override
-  void visitCheckLibraryIsLoaded(
-      CheckLibraryIsLoaded node, DartType typeContext) {}
+  ExpressionInferenceResult visitCheckLibraryIsLoaded(
+          CheckLibraryIsLoaded node, DartType typeContext) =>
+      new ExpressionInferenceResult(inferrer.coreTypes.objectClass.rawType);
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 2ffbade..36e77d4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -66,13 +66,7 @@
 import '../type_inference/type_inference_engine.dart'
     show IncludesTypeParametersNonCovariantly, TypeInferenceEngine;
 
-import '../type_inference/type_inferrer.dart'
-    show
-        ClosureContext,
-        ExpressionInferenceResult,
-        MethodContravarianceCheckKind,
-        TypeInferrer,
-        TypeInferrerImpl;
+import '../type_inference/type_inferrer.dart';
 
 import '../type_inference/type_promotion.dart'
     show TypePromoter, TypePromoterImpl, TypePromotionFact, TypePromotionScope;
@@ -115,9 +109,50 @@
   }
 }
 
+int getExtensionTypeParameterCount(Arguments arguments) {
+  if (arguments is ArgumentsJudgment) {
+    return arguments._extensionTypeParameterCount;
+  } else {
+    // TODO(johnniwinther): Remove this path or assert why it is accepted.
+    return 0;
+  }
+}
+
+int getExtensionTypeArgumentCount(Arguments arguments) {
+  if (arguments is ArgumentsJudgment) {
+    return arguments._extensionTypeArgumentCount;
+  } else {
+    // TODO(johnniwinther): Remove this path or assert why it is accepted.
+    return 0;
+  }
+}
+
+List<DartType> getExplicitExtensionTypeArguments(Arguments arguments) {
+  if (arguments is ArgumentsJudgment) {
+    if (arguments._extensionTypeArgumentCount == 0) {
+      return null;
+    } else {
+      return arguments.types
+          .take(arguments._extensionTypeArgumentCount)
+          .toList();
+    }
+  } else {
+    // TODO(johnniwinther): Remove this path or assert why it is accepted.
+    return null;
+  }
+}
+
 List<DartType> getExplicitTypeArguments(Arguments arguments) {
   if (arguments is ArgumentsJudgment) {
-    return arguments._hasExplicitTypeArguments ? arguments.types : null;
+    if (arguments._explicitTypeArgumentCount == 0) {
+      return null;
+    } else if (arguments._extensionTypeParameterCount == 0) {
+      return arguments.types;
+    } else {
+      return arguments.types
+          .skip(arguments._extensionTypeParameterCount)
+          .toList();
+    }
   } else {
     // This code path should only be taken in situations where there are no
     // type arguments at all, e.g. calling a user-definable operator.
@@ -146,25 +181,61 @@
 
 /// Concrete shadow object representing a set of invocation arguments.
 class ArgumentsJudgment extends Arguments {
-  bool _hasExplicitTypeArguments;
+  // TODO(johnniwinther): Move this to the static invocation instead.
+  final int _extensionTypeParameterCount;
+
+  final int _extensionTypeArgumentCount;
+
+  int _explicitTypeArgumentCount;
 
   List<Expression> get positionalJudgments => positional.cast();
 
   ArgumentsJudgment(List<Expression> positional,
       {List<DartType> types, List<NamedExpression> named})
-      : _hasExplicitTypeArguments = types != null && types.isNotEmpty,
+      : _explicitTypeArgumentCount = types?.length ?? 0,
+        _extensionTypeParameterCount = 0,
+        _extensionTypeArgumentCount = 0,
         super(positional, types: types, named: named);
 
+  ArgumentsJudgment.forExtensionMethod(int extensionTypeParameterCount,
+      int typeParameterCount, Expression receiver,
+      {List<DartType> extensionTypeArguments = const <DartType>[],
+      List<DartType> typeArguments = const <DartType>[],
+      List<Expression> positionalArguments = const <Expression>[],
+      List<NamedExpression> namedArguments = const <NamedExpression>[]})
+      : _extensionTypeParameterCount = extensionTypeParameterCount,
+        _extensionTypeArgumentCount = extensionTypeArguments.length,
+        _explicitTypeArgumentCount = typeArguments.length,
+        assert(
+            extensionTypeArguments.isEmpty ||
+                extensionTypeArguments.length == extensionTypeParameterCount,
+            "Extension type arguments must be empty or complete."),
+        super(<Expression>[receiver]..addAll(positionalArguments),
+            named: namedArguments,
+            types: <DartType>[]
+              ..addAll(_normalizeTypeArguments(
+                  extensionTypeParameterCount, extensionTypeArguments))
+              ..addAll(
+                  _normalizeTypeArguments(typeParameterCount, typeArguments)));
+
+  static List<DartType> _normalizeTypeArguments(
+      int length, List<DartType> arguments) {
+    if (arguments.isEmpty && length > 0) {
+      return new List<DartType>.filled(length, const UnknownType());
+    }
+    return arguments;
+  }
+
   static void setNonInferrableArgumentTypes(
       ArgumentsJudgment arguments, List<DartType> types) {
     arguments.types.clear();
     arguments.types.addAll(types);
-    arguments._hasExplicitTypeArguments = true;
+    arguments._explicitTypeArgumentCount = types.length;
   }
 
   static void removeNonInferrableArgumentTypes(ArgumentsJudgment arguments) {
     arguments.types.clear();
-    arguments._hasExplicitTypeArguments = false;
+    arguments._explicitTypeArgumentCount = 0;
   }
 }
 
@@ -280,7 +351,8 @@
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitCascadeJudgment(this, typeContext);
   }
 }
@@ -298,7 +370,7 @@
   Expression read;
 
   /// The expression appearing on the RHS of the assignment.
-  final Expression rhs;
+  Expression rhs;
 
   /// The expression that performs the write (e.g. `a.[]=(b, a.[](b) + 1)` in
   /// `++a[b]`).
@@ -358,19 +430,22 @@
           ?.addProblem(messageVoidExpression, read.fileOffset, noLength);
     }
     int writeOffset = write == null ? -1 : write.fileOffset;
-    Procedure combinerMember;
+    ObjectAccessTarget combinerTarget = const ObjectAccessTarget.unresolved();
     DartType combinedType;
     if (combiner != null) {
       bool isOverloadedArithmeticOperator = false;
-      combinerMember = inferrer.findMethodInvocationMember(readType, combiner,
+      combinerTarget = inferrer.findMethodInvocationMember(readType, combiner,
           instrumented: false);
-      if (combinerMember is Procedure) {
+      assert(!combinerTarget.isCallFunction);
+      if (combinerTarget.isInstanceMember &&
+          combinerTarget.member is Procedure) {
         isOverloadedArithmeticOperator = inferrer.typeSchemaEnvironment
-            .isOverloadedArithmeticOperatorAndType(combinerMember, readType);
+            .isOverloadedArithmeticOperatorAndType(
+                combinerTarget.member, readType);
       }
       DartType rhsType;
-      FunctionType combinerType = inferrer.getCalleeFunctionType(
-          inferrer.getCalleeType(combinerMember, readType), false);
+      FunctionType combinerType =
+          inferrer.getFunctionType(combinerTarget, readType, false);
       if (isPreIncDec || isPostIncDec) {
         rhsType = inferrer.coreTypes.intClass.rawType;
       } else {
@@ -380,8 +455,12 @@
         assert(identical(combiner.arguments.positional.first, rhs));
         // Analyzer uses a null context for the RHS here.
         // TODO(paulberry): improve on this.
-        inferrer.inferExpression(rhs, const UnknownType(), true);
-        rhsType = getInferredType(rhs, inferrer);
+        ExpressionInferenceResult rhsResult =
+            inferrer.inferExpression(rhs, const UnknownType(), true);
+        if (rhsResult.replacement != null) {
+          rhs = rhsResult.replacement;
+        }
+        rhsType = rhsResult.inferredType;
         // Do not use rhs after this point because it may be a Shadow node
         // that has been replaced in the tree with its desugaring.
         DartType expectedType = getPositionalParameterType(combinerType, 0);
@@ -396,7 +475,7 @@
       }
       MethodContravarianceCheckKind checkKind =
           inferrer.preCheckInvocationContravariance(read, readType,
-              combinerMember, combiner, combiner.arguments, combiner);
+              combinerTarget, combiner, combiner.arguments, combiner);
       Expression replacedCombiner = inferrer.handleInvocationContravariance(
           checkKind,
           combiner,
@@ -412,9 +491,13 @@
       }
       _storeLetType(inferrer, replacedCombiner, combinedType);
     } else {
-      inferrer.inferExpression(rhs, writeContext ?? const UnknownType(), true,
+      ExpressionInferenceResult rhsResult = inferrer.inferExpression(
+          rhs, writeContext ?? const UnknownType(), true,
           isVoidAllowed: true);
-      DartType rhsType = getInferredType(rhs, inferrer);
+      if (rhsResult.replacement != null) {
+        rhs = rhsResult.replacement;
+      }
+      DartType rhsType = rhsResult.inferredType;
       Expression replacedRhs = inferrer.ensureAssignable(
           writeContext, rhsType, rhs, writeOffset,
           isVoidAllowed: writeContext is VoidType);
@@ -441,7 +524,8 @@
     }
     inferredType =
         isPostIncDec ? (readType ?? const DynamicType()) : combinedType;
-    return new _ComplexAssignmentInferenceResult(combinerMember);
+    return new _ComplexAssignmentInferenceResult(
+        combinerTarget.member, inferredType);
   }
 }
 
@@ -503,10 +587,11 @@
   DeferredCheckJudgment(VariableDeclaration variable, Expression body)
       : super(variable, body);
 
-  Expression get judgment => body;
+  Expression get expression => body;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitDeferredCheckJudgment(this, typeContext);
   }
 }
@@ -530,7 +615,8 @@
   DoubleJudgment(double value) : super(value);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitDoubleJudgment(this, typeContext);
   }
 }
@@ -542,7 +628,8 @@
 
   /// Calls back to [inferrer] to perform type inference for whatever concrete
   /// type of [Expression] this is.
-  void acceptInference(InferenceVisitor visitor, DartType typeContext);
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext);
 }
 
 /// Concrete shadow object representing an empty statement in kernel form.
@@ -583,7 +670,8 @@
   ArgumentsJudgment get argumentJudgments => arguments;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitFactoryConstructorInvocationJudgment(this, typeContext);
   }
 }
@@ -698,7 +786,8 @@
   Expression get rightJudgment => body.then;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitIfNullJudgment(this, typeContext);
   }
 }
@@ -729,7 +818,8 @@
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitIllegalAssignmentJudgment(this, typeContext);
   }
 }
@@ -738,7 +828,7 @@
 /// `a[b]`.
 class IndexAssignmentJudgment extends ComplexAssignmentJudgmentWithReceiver {
   /// In an assignment to an index expression, the index expression.
-  final Expression index;
+  Expression index;
 
   IndexAssignmentJudgment._(Expression receiver, this.index, Expression rhs,
       {bool isSuper: false})
@@ -764,7 +854,8 @@
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitIndexAssignmentJudgment(this, typeContext);
   }
 }
@@ -780,11 +871,11 @@
 Expression checkWebIntLiteralsErrorIfUnexact(
     ShadowTypeInferrer inferrer, int value, String literal, int charOffset) {
   if (value >= 0 && value <= (1 << 53)) return null;
-  if (inferrer.library == null) return null;
+  if (inferrer.isTopLevel) return null;
   if (!inferrer.library.loader.target.backendTarget
       .errorOnUnexactWebIntLiterals) return null;
-  BigInt asInt = BigInt.from(value).toUnsigned(64);
-  BigInt asDouble = BigInt.from(asInt.toDouble());
+  BigInt asInt = new BigInt.from(value).toUnsigned(64);
+  BigInt asDouble = new BigInt.from(asInt.toDouble());
   if (asInt == asDouble) return null;
   String text = literal ?? value.toString();
   String nearest = text.startsWith('0x') || text.startsWith('0X')
@@ -808,13 +899,14 @@
 
   double asDouble({bool negated: false}) {
     if (value == 0 && negated) return -0.0;
-    BigInt intValue = BigInt.from(negated ? -value : value);
+    BigInt intValue = new BigInt.from(negated ? -value : value);
     double doubleValue = intValue.toDouble();
-    return intValue == BigInt.from(doubleValue) ? doubleValue : null;
+    return intValue == new BigInt.from(doubleValue) ? doubleValue : null;
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitIntJudgment(this, typeContext);
   }
 }
@@ -834,7 +926,7 @@
     double doubleValue = intValue.toDouble();
     return !doubleValue.isNaN &&
             !doubleValue.isInfinite &&
-            intValue == BigInt.from(doubleValue)
+            intValue == new BigInt.from(doubleValue)
         ? doubleValue
         : null;
   }
@@ -844,7 +936,8 @@
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitShadowLargeIntLiteral(this, typeContext);
   }
 }
@@ -890,7 +983,8 @@
         super(expressions, typeArgument: typeArgument, isConst: isConst);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitListLiteralJudgment(this, typeContext);
   }
 }
@@ -905,7 +999,8 @@
         super(expressions, typeArgument: typeArgument, isConst: isConst);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitSetLiteralJudgment(this, typeContext);
   }
 }
@@ -922,7 +1017,8 @@
             keyType: keyType, valueType: valueType, isConst: isConst);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitMapLiteralJudgment(this, typeContext);
   }
 }
@@ -945,7 +1041,8 @@
   ArgumentsJudgment get argumentJudgments => arguments;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitMethodInvocationJudgment(this, typeContext);
   }
 }
@@ -969,7 +1066,8 @@
   VariableDeclarationJudgment get variableJudgment => variable;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitNamedFunctionExpressionJudgment(this, typeContext);
   }
 }
@@ -994,7 +1092,8 @@
   MethodInvocation get _desugaredInvocation => body.otherwise;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitNullAwareMethodInvocationJudgment(this, typeContext);
   }
 }
@@ -1020,7 +1119,8 @@
   Expression get receiverJudgment => variable.initializer;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitNullAwarePropertyGetJudgment(this, typeContext);
   }
 }
@@ -1042,13 +1142,14 @@
     return parts;
   }
 
-  Object _handleWriteContravariance(
+  ObjectAccessTarget _handleWriteContravariance(
       ShadowTypeInferrer inferrer, DartType receiverType) {
     return inferrer.findPropertySetMember(receiverType, write);
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitPropertyAssignmentJudgment(this, typeContext);
   }
 }
@@ -1071,10 +1172,9 @@
 
 /// Concrete shadow object representing a return statement in kernel form.
 class ReturnJudgment extends ReturnStatement implements StatementJudgment {
-  final String returnKeywordLexeme;
+  final bool isArrow;
 
-  ReturnJudgment(this.returnKeywordLexeme, [Expression expression])
-      : super(expression);
+  ReturnJudgment(this.isArrow, [Expression expression]) : super(expression);
 
   Expression get judgment => expression;
 
@@ -1097,7 +1197,8 @@
   StaticAssignmentJudgment._(Expression rhs) : super._(rhs);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitStaticAssignmentJudgment(this, typeContext);
   }
 }
@@ -1128,7 +1229,8 @@
   ArgumentsJudgment get argumentJudgments => arguments;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitSuperMethodInvocationJudgment(this, typeContext);
   }
 }
@@ -1142,7 +1244,8 @@
       : super(name, interfaceTarget);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitSuperPropertyGetJudgment(this, typeContext);
   }
 }
@@ -1185,7 +1288,8 @@
   SymbolLiteralJudgment(String value) : super(value);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitSymbolLiteralJudgment(this, typeContext);
   }
 }
@@ -1205,7 +1309,8 @@
   ArgumentsJudgment get argumentJudgments => arguments;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitInvalidConstructorInvocationJudgment(this, typeContext);
   }
 }
@@ -1219,7 +1324,8 @@
       : super._(desugared);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitInvalidWriteJudgment(this, typeContext);
   }
 }
@@ -1245,15 +1351,17 @@
   }
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitSyntheticExpressionJudgment(this, typeContext);
   }
 
   /// Removes this expression from the expression tree, replacing it with
   /// [desugared].
-  void _replaceWithDesugared() {
+  Expression _replaceWithDesugared() {
     parent.replaceChild(this, desugared);
     parent = null;
+    return desugared;
   }
 
   /// Updates any [Let] nodes in the desugared expression to account for the
@@ -1287,17 +1395,17 @@
   }
 
   @override
-  accept(ExpressionVisitor<dynamic> v) {
+  R accept<R>(ExpressionVisitor<R> v) {
     // This is designed to throw an exception during serialization. It can also
     // lead to exceptions during transformations, but we have to accept a
     // [Transformer] as this is used to implement `replaceChild`.
     if (v is Transformer) return super.accept(v);
-    unsupported("accept", fileOffset, getFileUri(this));
+    throw unsupported("accept", fileOffset, getFileUri(this));
   }
 
   @override
-  accept1(ExpressionVisitor1<dynamic, dynamic> v, arg) {
-    unsupported("accept1", fileOffset, getFileUri(this));
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) {
+    throw unsupported("accept1", fileOffset, getFileUri(this));
   }
 
   @override
@@ -1376,7 +1484,7 @@
   }
 
   @override
-  DartType inferExpression(
+  ExpressionInferenceResult inferExpression(
       kernel.Expression expression, DartType typeContext, bool typeNeeded,
       {bool isVoidAllowed: false}) {
     // `null` should never be used as the type context.  An instance of
@@ -1395,22 +1503,24 @@
     // When doing top level inference, we skip subexpressions whose type isn't
     // needed so that we don't induce bogus dependencies on fields mentioned in
     // those subexpressions.
-    if (!typeNeeded) return null;
+    if (!typeNeeded) return const ExpressionInferenceResult(null);
 
     InferenceVisitor visitor = new InferenceVisitor(this);
+    ExpressionInferenceResult result;
     if (expression is ExpressionJudgment) {
-      expression.acceptInference(visitor, typeContext);
+      result = expression.acceptInference(visitor, typeContext);
     } else {
-      expression.accept1(visitor, typeContext);
+      result = expression.accept1(visitor, typeContext);
     }
-    DartType inferredType = getInferredType(expression, this);
+    DartType inferredType = result.inferredType;
+    assert(inferredType != null, "No type inferred for $expression.");
     if (inferredType is VoidType && !isVoidAllowed) {
       if (expression.parent is! ArgumentsJudgment) {
         helper?.addProblem(
             messageVoidExpression, expression.fileOffset, noLength);
       }
     }
-    return inferredType;
+    return result;
   }
 
   @override
@@ -1462,7 +1572,8 @@
   TypeLiteralJudgment(DartType type) : super(type);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitTypeLiteralJudgment(this, typeContext);
   }
 }
@@ -1540,7 +1651,8 @@
   VariableAssignmentJudgment._(Expression rhs) : super._(rhs);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitVariableAssignmentJudgment(this, typeContext);
   }
 }
@@ -1598,9 +1710,9 @@
         _isLocalFunction = false,
         super.forValue(initializer);
 
-  VariableDeclarationJudgment.forValue(
-      Expression initializer, this._functionNestingLevel)
+  VariableDeclarationJudgment.forValue(Expression initializer)
       : forSyntheticToken = false,
+        _functionNestingLevel = 0,
         _implicitlyTyped = true,
         _isLocalFunction = false,
         super.forValue(initializer);
@@ -1639,7 +1751,8 @@
       : super._(desugared);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitUnresolvedTargetInvocationJudgment(this, typeContext);
   }
 }
@@ -1655,7 +1768,8 @@
       : super._(desugared);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitUnresolvedVariableAssignmentJudgment(this, typeContext);
   }
 }
@@ -1672,7 +1786,8 @@
       : super(variable);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitVariableGetJudgment(this, typeContext);
   }
 }
@@ -1713,7 +1828,8 @@
   ArgumentsJudgment get argumentJudgments => arguments;
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitLoadLibraryJudgment(this, typeContext);
   }
 }
@@ -1728,7 +1844,8 @@
   LoadLibraryTearOffJudgment(this.import, Procedure target) : super(target);
 
   @override
-  void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
     return visitor.visitLoadLibraryTearOffJudgment(this, typeContext);
   }
 }
@@ -1739,13 +1856,16 @@
   /// `null` if the assignment is not compound.
   final Procedure combiner;
 
-  _ComplexAssignmentInferenceResult(this.combiner);
+  /// The inferred type of the RHS.
+  final DartType inferredType;
+
+  _ComplexAssignmentInferenceResult(this.combiner, this.inferredType);
 }
 
 class _UnfinishedCascade extends Expression {
-  accept(v) => unsupported("accept", -1, null);
+  R accept<R>(v) => unsupported("accept", -1, null);
 
-  accept1(v, arg) => unsupported("accept1", -1, null);
+  R accept1<R, A>(v, arg) => unsupported("accept1", -1, null);
 
   getStaticType(types) => unsupported("getStaticType", -1, null);
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index ab78a04..8755030 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -95,6 +95,7 @@
         NamedTypeBuilder,
         ProcedureBuilder,
         LibraryBuilder,
+        NullabilityBuilder,
         TypeBuilder,
         TypeDeclarationBuilder;
 
@@ -120,11 +121,16 @@
 
   Component component;
 
-  final TypeBuilder dynamicType = new NamedTypeBuilder("dynamic", null);
+  // 'dynamic' is always nullable.
+  final TypeBuilder dynamicType = new NamedTypeBuilder(
+      "dynamic", const NullabilityBuilder.nullable(), null);
 
-  final NamedTypeBuilder objectType = new NamedTypeBuilder("Object", null);
+  final NamedTypeBuilder objectType =
+      new NamedTypeBuilder("Object", const NullabilityBuilder.omitted(), null);
 
-  final TypeBuilder bottomType = new NamedTypeBuilder("Null", null);
+  // Null is always nullable.
+  final TypeBuilder bottomType =
+      new NamedTypeBuilder("Null", const NullabilityBuilder.nullable(), null);
 
   bool get legacyMode => backendTarget.legacyMode;
 
@@ -230,12 +236,13 @@
   }
 
   void breakCycle(ClassBuilder builder) {
-    Class cls = builder.target;
+    Class cls = builder.cls;
     cls.implementedTypes.clear();
     cls.supertype = null;
     cls.mixedInType = null;
-    builder.supertype = new NamedTypeBuilder("Object", null)
-      ..bind(objectClassBuilder);
+    builder.supertype =
+        new NamedTypeBuilder("Object", const NullabilityBuilder.omitted(), null)
+          ..bind(objectClassBuilder);
     builder.interfaces = null;
     builder.mixedInType = null;
   }
@@ -350,7 +357,7 @@
         declaration = problem.getFirstDeclaration();
       }
       if (declaration is ProcedureBuilder) {
-        component.mainMethod = declaration.procedure;
+        component.mainMethod = declaration.actualProcedure;
       } else if (declaration is DillMemberBuilder) {
         if (declaration.member is Procedure) {
           component.mainMethod = declaration.member;
@@ -374,10 +381,11 @@
         while (iterator.moveNext()) {
           Builder declaration = iterator.current;
           if (declaration is SourceClassBuilder) {
-            Class cls = declaration.target;
+            Class cls = declaration.cls;
             if (cls != objectClass) {
               cls.supertype ??= objectClass.asRawSupertype;
-              declaration.supertype ??= new NamedTypeBuilder("Object", null)
+              declaration.supertype ??= new NamedTypeBuilder(
+                  "Object", const NullabilityBuilder.omitted(), null)
                 ..bind(objectClassBuilder);
             }
             if (declaration.isMixinApplication) {
@@ -394,7 +402,7 @@
   void installSyntheticConstructors(List<SourceClassBuilder> builders) {
     Class objectClass = this.objectClass;
     for (SourceClassBuilder builder in builders) {
-      if (builder.target != objectClass && !builder.isPatch) {
+      if (builder.cls != objectClass && !builder.isPatch) {
         if (builder.isPatch ||
             builder.isMixinDeclaration ||
             builder.isExtension) {
@@ -419,9 +427,9 @@
     assert(!builder.isMixinApplication);
     assert(!builder.isExtension);
     // TODO(askesc): Make this check light-weight in the absence of patches.
-    if (builder.target.constructors.isNotEmpty) return;
-    if (builder.target.redirectingFactoryConstructors.isNotEmpty) return;
-    for (Procedure proc in builder.target.procedures) {
+    if (builder.cls.constructors.isNotEmpty) return;
+    if (builder.cls.redirectingFactoryConstructors.isNotEmpty) return;
+    for (Procedure proc in builder.cls.procedures) {
       if (proc.isFactory) return;
     }
 
@@ -430,13 +438,13 @@
     /// >Iff no constructor is specified for a class C, it implicitly has a
     /// >default constructor C() : super() {}, unless C is class Object.
     // The superinitializer is installed below in [finishConstructors].
-    builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+    builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
   }
 
   void installForwardingConstructors(SourceClassBuilder builder) {
     assert(builder.isMixinApplication);
     if (builder.library.loader != loader) return;
-    if (builder.target.constructors.isNotEmpty) {
+    if (builder.cls.constructors.isNotEmpty) {
       // These were installed by a subclass in the recursive call below.
       return;
     }
@@ -465,17 +473,17 @@
     }
     if (supertype is ClassBuilder) {
       if (supertype.cls.constructors.isEmpty) {
-        builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+        builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
       } else {
         Map<TypeParameter, DartType> substitutionMap =
-            builder.getSubstitutionMap(supertype.target);
+            builder.getSubstitutionMap(supertype.cls);
         for (Constructor constructor in supertype.cls.constructors) {
           builder.addSyntheticConstructor(makeMixinApplicationConstructor(
-              builder.target, builder.cls.mixin, constructor, substitutionMap));
+              builder.cls, builder.cls.mixin, constructor, substitutionMap));
         }
       }
     } else if (supertype is InvalidTypeBuilder) {
-      builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+      builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
     } else {
       unhandled("${supertype.runtimeType}", "installForwardingConstructors",
           builder.charOffset, builder.fileUri);
@@ -564,19 +572,16 @@
 
   void computeCoreTypes() {
     List<Library> libraries = <Library>[];
-    for (String platformLibrary in const [
+    for (String platformLibrary in [
       "dart:_internal",
       "dart:async",
-      // TODO(askesc): When all backends support set literals, we no longer
-      // need to index dart:collection, as it is only needed for desugaring of
-      // const sets. We can remove it from this list at that time.
-      "dart:collection",
       "dart:core",
-      "dart:mirrors"
+      "dart:mirrors",
+      ...backendTarget.extraIndexedLibraries
     ]) {
       Uri uri = Uri.parse(platformLibrary);
-      LibraryBuilder library = loader.builders[uri];
-      if (library == null) {
+      LibraryBuilder libraryBuilder = loader.builders[uri];
+      if (libraryBuilder == null) {
         // TODO(ahe): This is working around a bug in kernel_driver_test or
         // kernel_driver.
         bool found = false;
@@ -592,7 +597,7 @@
           throw "Can't find $uri";
         }
       } else {
-        libraries.add(library.target);
+        libraries.add(libraryBuilder.library);
       }
     }
     Component platformLibraries =
@@ -605,7 +610,7 @@
   void finishAllConstructors(List<SourceClassBuilder> builders) {
     Class objectClass = this.objectClass;
     for (SourceClassBuilder builder in builders) {
-      Class cls = builder.target;
+      Class cls = builder.cls;
       if (cls != objectClass) {
         finishConstructors(builder);
       }
@@ -613,11 +618,11 @@
     ticker.logMs("Finished constructors");
   }
 
-  /// Ensure constructors of [cls] have the correct initializers and other
+  /// Ensure constructors of [builder] have the correct initializers and other
   /// requirements.
   void finishConstructors(SourceClassBuilder builder) {
     if (builder.isPatch) return;
-    Class cls = builder.target;
+    Class cls = builder.cls;
 
     /// Quotes below are from [Dart Programming Language Specification, 4th
     /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
@@ -783,19 +788,19 @@
         loader.libraries,
         new KernelDiagnosticReporter(loader),
         logger: (String msg) => ticker.logMs(msg));
-    if (loader.target.enableConstantUpdate2018) {
-      TypeEnvironment environment =
-          new TypeEnvironment(loader.coreTypes, loader.hierarchy);
-      constants.transformLibraries(
-          loader.libraries,
-          backendTarget.constantsBackend(loader.coreTypes),
-          environmentDefines,
-          environment,
-          new KernelConstantErrorReporter(loader),
-          desugarSets: !backendTarget.supportsSetLiterals,
-          errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
-      ticker.logMs("Evaluated constants");
-    }
+
+    TypeEnvironment environment =
+        new TypeEnvironment(loader.coreTypes, loader.hierarchy);
+    constants.transformLibraries(
+        loader.libraries,
+        backendTarget.constantsBackend(loader.coreTypes),
+        environmentDefines,
+        environment,
+        new KernelConstantErrorReporter(loader),
+        desugarSets: !backendTarget.supportsSetLiterals,
+        errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
+    ticker.logMs("Evaluated constants");
+
     backendTarget.performModularTransformationsOnLibraries(
         component,
         loader.coreTypes,
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 c4e8e9998..c22f4d5 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
@@ -51,12 +51,12 @@
     LoadLibrary expression = createLoadLibrary(charOffset, forest, null);
     String prefix = expression.import.name;
     tearoff = new Procedure(
-        new Name('__loadLibrary_$prefix', parent.target),
+        new Name('__loadLibrary_$prefix', parent.library),
         ProcedureKind.Method,
         new FunctionNode(new ReturnStatement(expression),
             returnType: new InterfaceType(parent.loader.coreTypes.futureClass,
                 <DartType>[const DynamicType()])),
-        fileUri: parent.target.fileUri,
+        fileUri: parent.library.fileUri,
         isStatic: true)
       ..startFileOffset = charOffset
       ..fileOffset = charOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index 6cab740..e7d57d6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -113,7 +113,7 @@
     int i = 0;
     for (; i < elements.length; ++i) {
       if (elements[i] is ControlFlowElement) break;
-      elements[i] = elements[i].accept(this)..parent = node;
+      elements[i] = elements[i].accept<TreeNode>(this)..parent = node;
     }
 
     // If there were only expressions, we are done.
@@ -159,7 +159,8 @@
     } else if (element is ForInElement) {
       _translateForInElement(element, elementType, isSet, result, body);
     } else {
-      _addExpressionElement(element.accept(this), isSet, result, body);
+      _addExpressionElement(
+          element.accept<TreeNode>(this), isSet, result, body);
     }
   }
 
@@ -190,7 +191,8 @@
           ? elseStatements.first
           : new Block(elseStatements);
     }
-    body.add(new IfStatement(element.condition.accept(this), thenBody, elseBody)
+    body.add(new IfStatement(
+        element.condition.accept<TreeNode>(this), thenBody, elseBody)
       ..fileOffset = element.fileOffset);
   }
 
@@ -201,7 +203,7 @@
     Statement loopBody =
         statements.length == 1 ? statements.first : new Block(statements);
     ForStatement loop = new ForStatement(element.variables,
-        element.condition?.accept(this), element.updates, loopBody)
+        element.condition?.accept<TreeNode>(this), element.updates, loopBody)
       ..fileOffset = element.fileOffset;
     transformList(loop.variables, this, loop);
     transformList(loop.updates, this, loop);
@@ -215,7 +217,7 @@
     if (prologue == null) {
       statements = <Statement>[];
     } else {
-      prologue = prologue.accept(this);
+      prologue = prologue.accept<TreeNode>(this);
       statements =
           prologue is Block ? prologue.statements : <Statement>[prologue];
     }
@@ -223,17 +225,17 @@
     Statement loopBody =
         statements.length == 1 ? statements.first : new Block(statements);
     if (element.problem != null) {
-      body.add(new ExpressionStatement(element.problem.accept(this)));
+      body.add(new ExpressionStatement(element.problem.accept<TreeNode>(this)));
     }
     body.add(new ForInStatement(
-        element.variable, element.iterable.accept(this), loopBody,
+        element.variable, element.iterable.accept<TreeNode>(this), loopBody,
         isAsync: element.isAsync)
       ..fileOffset = element.fileOffset);
   }
 
   void _translateSpreadElement(SpreadElement element, DartType elementType,
       bool isSet, VariableDeclaration result, List<Statement> body) {
-    Expression value = element.expression.accept(this);
+    Expression value = element.expression.accept<TreeNode>(this);
     // Null-aware spreads require testing the subexpression's value.
     VariableDeclaration temp;
     if (element.isNullAware) {
@@ -314,7 +316,7 @@
     int i = 0;
     for (; i < node.entries.length; ++i) {
       if (node.entries[i] is ControlFlowMapEntry) break;
-      node.entries[i] = node.entries[i].accept(this)..parent = node;
+      node.entries[i] = node.entries[i].accept<TreeNode>(this)..parent = node;
     }
 
     // If there were no control-flow entries we are done.
@@ -350,7 +352,7 @@
     } else if (entry is ForInMapEntry) {
       _translateForInEntry(entry, keyType, valueType, result, body);
     } else {
-      _addNormalEntry(entry.accept(this), result, body);
+      _addNormalEntry(entry.accept<TreeNode>(this), result, body);
     }
   }
 
@@ -380,7 +382,7 @@
           elseBody.length == 1 ? elseBody.first : new Block(elseBody);
     }
     body.add(new IfStatement(
-        entry.condition.accept(this), thenStatement, elseStatement));
+        entry.condition.accept<TreeNode>(this), thenStatement, elseStatement));
   }
 
   void _translateForEntry(ForMapEntry entry, DartType keyType,
@@ -389,8 +391,8 @@
     _translateEntry(entry.body, keyType, valueType, result, statements);
     Statement loopBody =
         statements.length == 1 ? statements.first : new Block(statements);
-    ForStatement loop = new ForStatement(
-        entry.variables, entry.condition?.accept(this), entry.updates, loopBody)
+    ForStatement loop = new ForStatement(entry.variables,
+        entry.condition?.accept<TreeNode>(this), entry.updates, loopBody)
       ..fileOffset = entry.fileOffset;
     transformList(loop.variables, this, loop);
     transformList(loop.updates, this, loop);
@@ -404,7 +406,7 @@
     if (prologue == null) {
       statements = <Statement>[];
     } else {
-      prologue = prologue.accept(this);
+      prologue = prologue.accept<TreeNode>(this);
       statements =
           prologue is Block ? prologue.statements : <Statement>[prologue];
     }
@@ -412,17 +414,17 @@
     Statement loopBody =
         statements.length == 1 ? statements.first : new Block(statements);
     if (entry.problem != null) {
-      body.add(new ExpressionStatement(entry.problem.accept(this)));
+      body.add(new ExpressionStatement(entry.problem.accept<TreeNode>(this)));
     }
     body.add(new ForInStatement(
-        entry.variable, entry.iterable.accept(this), loopBody,
+        entry.variable, entry.iterable.accept<TreeNode>(this), loopBody,
         isAsync: entry.isAsync)
       ..fileOffset = entry.fileOffset);
   }
 
   void _translateSpreadEntry(SpreadMapEntry entry, DartType keyType,
       DartType valueType, VariableDeclaration result, List<Statement> body) {
-    Expression value = entry.expression.accept(this);
+    Expression value = entry.expression.accept<TreeNode>(this);
     // Null-aware spreads require testing the subexpression's value.
     VariableDeclaration temp;
     if (entry.isNullAware) {
@@ -499,7 +501,7 @@
     int i = 0;
     for (; i < elements.length; ++i) {
       if (elements[i] is ControlFlowElement) break;
-      elements[i] = elements[i].accept(this)..parent = node;
+      elements[i] = elements[i].accept<TreeNode>(this)..parent = node;
     }
 
     // If there were only expressions, we are done.
@@ -524,7 +526,7 @@
           parts.add(makeLiteral(currentPart));
           currentPart = null;
         }
-        Expression spreadExpression = element.expression.accept(this);
+        Expression spreadExpression = element.expression.accept<TreeNode>(this);
         if (element.isNullAware) {
           VariableDeclaration temp =
               new VariableDeclaration(null, initializer: spreadExpression);
@@ -544,10 +546,10 @@
           parts.add(makeLiteral(currentPart));
           currentPart = null;
         }
-        Expression condition = element.condition.accept(this);
-        Expression then = makeLiteral([element.then]).accept(this);
+        Expression condition = element.condition.accept<TreeNode>(this);
+        Expression then = makeLiteral([element.then]).accept<TreeNode>(this);
         Expression otherwise = element.otherwise != null
-            ? makeLiteral([element.otherwise]).accept(this)
+            ? makeLiteral([element.otherwise]).accept<TreeNode>(this)
             : makeLiteral([]);
         parts.add(new ConditionalExpression(
             condition, then, otherwise, const DynamicType()));
@@ -557,7 +559,7 @@
             element.fileOffset, getFileUri(element));
       } else {
         currentPart ??= <Expression>[];
-        currentPart.add(element.accept(this));
+        currentPart.add(element.accept<TreeNode>(this));
       }
     }
     if (currentPart != null) {
@@ -573,7 +575,7 @@
     int i = 0;
     for (; i < node.entries.length; ++i) {
       if (node.entries[i] is ControlFlowMapEntry) break;
-      node.entries[i] = node.entries[i].accept(this)..parent = node;
+      node.entries[i] = node.entries[i].accept<TreeNode>(this)..parent = node;
     }
 
     // If there were no control-flow entries we are done.
@@ -595,7 +597,7 @@
           parts.add(makeLiteral(currentPart));
           currentPart = null;
         }
-        Expression spreadExpression = entry.expression.accept(this);
+        Expression spreadExpression = entry.expression.accept<TreeNode>(this);
         if (entry.isNullAware) {
           VariableDeclaration temp =
               new VariableDeclaration(null, initializer: spreadExpression);
@@ -615,10 +617,10 @@
           parts.add(makeLiteral(currentPart));
           currentPart = null;
         }
-        Expression condition = entry.condition.accept(this);
-        Expression then = makeLiteral([entry.then]).accept(this);
+        Expression condition = entry.condition.accept<TreeNode>(this);
+        Expression then = makeLiteral([entry.then]).accept<TreeNode>(this);
         Expression otherwise = entry.otherwise != null
-            ? makeLiteral([entry.otherwise]).accept(this)
+            ? makeLiteral([entry.otherwise]).accept<TreeNode>(this)
             : makeLiteral([]);
         parts.add(new ConditionalExpression(
             condition, then, otherwise, const DynamicType()));
@@ -628,7 +630,7 @@
             entry.fileOffset, getFileUri(entry));
       } else {
         currentPart ??= <MapEntry>[];
-        currentPart.add(entry.accept(this));
+        currentPart.add(entry.accept<TreeNode>(this));
       }
     }
     if (currentPart != null) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
index 3480b2b..ab150cf 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
@@ -9,19 +9,11 @@
 import 'package:kernel/ast.dart'
     show
         Arguments,
-        Class,
-        Constructor,
-        ConstructorInvocation,
-        DartType,
         Expression,
         InterfaceType,
         Let,
-        Library,
-        MapEntry,
-        MapLiteral,
         MethodInvocation,
         Name,
-        NullLiteral,
         Procedure,
         SetLiteral,
         StaticInvocation,
@@ -40,11 +32,8 @@
 // TODO(askesc): Delete this class when all backends support set literals.
 class SetLiteralTransformer extends Transformer {
   final CoreTypes coreTypes;
-  final DartType nullType;
   final Procedure setFactory;
   final Procedure addMethod;
-  final Constructor unmodifiableSetConstructor;
-  final bool transformConst;
 
   static Procedure _findSetFactory(CoreTypes coreTypes) {
     Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
@@ -56,68 +45,32 @@
     return coreTypes.index.getMember('dart:core', 'Set', 'add');
   }
 
-  static Constructor _findUnmodifiableSetConstructor(SourceLoader loader) {
-    // We should not generally dig into libraries like this, and we should
-    // avoid dependencies on libraries other than the ones indexed by
-    // CoreTypes. This is a temporary solution until all backends have
-    // implemented support for set literals.
-    Uri collectionUri = Uri.parse("dart:collection");
-    Library collectionLibrary = loader.builders[collectionUri].target;
-    for (int i = 0; i < collectionLibrary.classes.length; i++) {
-      Class classNode = collectionLibrary.classes[i];
-      if (classNode.name == "_UnmodifiableSet") {
-        for (int j = 0; j < collectionLibrary.classes.length; j++) {
-          Constructor constructor = classNode.constructors[j];
-          if (constructor.name.name.isEmpty) {
-            return constructor;
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  SetLiteralTransformer(SourceLoader loader, {this.transformConst: true})
+  SetLiteralTransformer(SourceLoader loader)
       : coreTypes = loader.coreTypes,
-        nullType = new InterfaceType(loader.coreTypes.nullClass, []),
         setFactory = _findSetFactory(loader.coreTypes),
-        addMethod = _findAddMethod(loader.coreTypes),
-        unmodifiableSetConstructor = _findUnmodifiableSetConstructor(loader);
+        addMethod = _findAddMethod(loader.coreTypes);
 
   TreeNode visitSetLiteral(SetLiteral node) {
-    if (node.isConst) {
-      if (!transformConst) return node;
-      List<MapEntry> entries = new List<MapEntry>(node.expressions.length);
-      for (int i = 0; i < node.expressions.length; i++) {
-        // expression_i: null
-        Expression entry = node.expressions[i].accept(this);
-        entries[i] = new MapEntry(entry, new NullLiteral());
-      }
-      Expression mapExp = new MapLiteral(entries,
-          keyType: node.typeArgument, valueType: nullType, isConst: true);
-      return new ConstructorInvocation(unmodifiableSetConstructor,
-          new Arguments([mapExp], types: [node.typeArgument]),
-          isConst: true);
-    } else {
-      // Outermost declaration of let chain: Set<E> setVar = new Set<E>();
-      VariableDeclaration setVar = new VariableDeclaration.forValue(
-          new StaticInvocation(
-              setFactory, new Arguments([], types: [node.typeArgument])),
-          type: new InterfaceType(coreTypes.setClass, [node.typeArgument]));
-      // Innermost body of let chain: setVar
-      Expression setExp = new VariableGet(setVar);
-      for (int i = node.expressions.length - 1; i >= 0; i--) {
-        // let _ = setVar.add(expression) in rest
-        Expression entry = node.expressions[i].accept(this);
-        setExp = new Let(
-            new VariableDeclaration.forValue(new MethodInvocation(
-                new VariableGet(setVar),
-                new Name("add"),
-                new Arguments([entry]),
-                addMethod)),
-            setExp);
-      }
-      return new Let(setVar, setExp);
+    if (node.isConst) return node;
+
+    // Outermost declaration of let chain: Set<E> setVar = new Set<E>();
+    VariableDeclaration setVar = new VariableDeclaration.forValue(
+        new StaticInvocation(
+            setFactory, new Arguments([], types: [node.typeArgument])),
+        type: new InterfaceType(coreTypes.setClass, [node.typeArgument]));
+    // Innermost body of let chain: setVar
+    Expression setExp = new VariableGet(setVar);
+    for (int i = node.expressions.length - 1; i >= 0; i--) {
+      // let _ = setVar.add(expression) in rest
+      Expression entry = node.expressions[i].accept<TreeNode>(this);
+      setExp = new Let(
+          new VariableDeclaration.forValue(new MethodInvocation(
+              new VariableGet(setVar),
+              new Name("add"),
+              new Arguments([entry]),
+              addMethod)),
+          setExp);
     }
+    return new Let(setVar, setExp);
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index 58bd5a7..e176829 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -145,7 +145,8 @@
       }
     }
     if (arguments != null) {
-      return new NamedTypeBuilder(type.name, arguments)..bind(type.declaration);
+      return new NamedTypeBuilder(type.name, type.nullabilityBuilder, arguments)
+        ..bind(type.declaration);
     }
     return type;
   }
@@ -411,7 +412,7 @@
       TypeDeclarationBuilder declaration = type.declaration;
       if (declaration is DillClassBuilder) {
         bool hasInbound = false;
-        List<TypeParameter> typeParameters = declaration.target.typeParameters;
+        List<TypeParameter> typeParameters = declaration.cls.typeParameters;
         for (int i = 0; i < typeParameters.length && !hasInbound; ++i) {
           if (containsTypeVariable(
               typeParameters[i].bound, typeParameters.toSet())) {
@@ -424,7 +425,7 @@
         }
       } else if (declaration is DillTypeAliasBuilder) {
         bool hasInbound = false;
-        List<TypeParameter> typeParameters = declaration.target.typeParameters;
+        List<TypeParameter> typeParameters = declaration.typedef.typeParameters;
         for (int i = 0; i < typeParameters.length && !hasInbound; ++i) {
           if (containsTypeVariable(
               typeParameters[i].bound, typeParameters.toSet())) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index ba72be2..5f6dfb0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -30,6 +30,7 @@
         NamedTypeBuilder,
         TypeVariableBuilder,
         LibraryBuilder,
+        NullabilityBuilder,
         TypeBuilder,
         VoidTypeBuilder;
 
@@ -51,13 +52,17 @@
   }
 
   TypeBuilder visitDynamicType(DynamicType node) {
-    return new NamedTypeBuilder("dynamic", null)
+    // 'dynamic' is always nullable.
+    return new NamedTypeBuilder(
+        "dynamic", const NullabilityBuilder.nullable(), null)
       ..bind(
           new DynamicTypeBuilder(const DynamicType(), loader.coreLibrary, -1));
   }
 
   TypeBuilder visitVoidType(VoidType node) {
-    return new NamedTypeBuilder("void", null)
+    // 'void' is always nullable.
+    return new NamedTypeBuilder(
+        "void", const NullabilityBuilder.nullable(), null)
       ..bind(new VoidTypeBuilder(const VoidType(), loader.coreLibrary, -1));
   }
 
@@ -76,7 +81,11 @@
         arguments[i] = kernelArguments[i].accept(this);
       }
     }
-    return new NamedTypeBuilder(cls.name, arguments)..bind(cls);
+    // TODO(dmitryas): Compute the nullabilityBuilder field for the result from
+    //  the nullability field of 'node'.
+    return new NamedTypeBuilder(
+        cls.name, const NullabilityBuilder.pendingImplementation(), arguments)
+      ..bind(cls);
   }
 
   @override
@@ -114,7 +123,10 @@
     Class kernelClass = parameter.parent;
     Library kernelLibrary = kernelClass.enclosingLibrary;
     LibraryBuilder library = loader.builders[kernelLibrary.importUri];
-    return new NamedTypeBuilder(parameter.name, null)
+    // TODO(dmitryas): Compute the nullabilityBuilder field for the result from
+    //  the nullability field of 'node'.
+    return new NamedTypeBuilder(
+        parameter.name, const NullabilityBuilder.pendingImplementation(), null)
       ..bind(new TypeVariableBuilder.fromKernel(parameter, library));
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/types.dart b/pkg/front_end/lib/src/fasta/kernel/types.dart
index de2ee77..a70d416 100644
--- a/pkg/front_end/lib/src/fasta/kernel/types.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/types.dart
@@ -57,10 +57,10 @@
     }
     if (t is InterfaceType) {
       Class cls = t.classNode;
-      if (cls == hierarchy.objectKernelClass) {
+      if (cls == hierarchy.objectClass) {
         return true; // Rule 2.
       }
-      if (cls == hierarchy.futureOrKernelClass) {
+      if (cls == hierarchy.futureOrClass) {
         const IsFutureOrSubtypeOf relation = const IsFutureOrSubtypeOf();
         if (s is DynamicType) {
           return relation.isDynamicRelated(
@@ -68,7 +68,7 @@
         } else if (s is VoidType) {
           return relation.isVoidRelated(s, sNullability, t, tNullability, this);
         } else if (s is InterfaceType) {
-          return s.classNode == hierarchy.futureOrKernelClass
+          return s.classNode == hierarchy.futureOrClass
               ? relation.isFutureOrRelated(
                   s, sNullability, t, tNullability, this)
               : relation.isInterfaceRelated(
@@ -94,7 +94,7 @@
         } else if (s is VoidType) {
           return relation.isVoidRelated(s, sNullability, t, tNullability, this);
         } else if (s is InterfaceType) {
-          return s.classNode == hierarchy.futureOrKernelClass
+          return s.classNode == hierarchy.futureOrClass
               ? relation.isFutureOrRelated(
                   s, sNullability, t, tNullability, this)
               : relation.isInterfaceRelated(
@@ -121,7 +121,7 @@
       } else if (s is VoidType) {
         return relation.isVoidRelated(s, sNullability, t, tNullability, this);
       } else if (s is InterfaceType) {
-        return s.classNode == hierarchy.futureOrKernelClass
+        return s.classNode == hierarchy.futureOrClass
             ? relation.isFutureOrRelated(s, sNullability, t, tNullability, this)
             : relation.isInterfaceRelated(
                 s, sNullability, t, tNullability, this);
@@ -148,7 +148,7 @@
         } else if (s is VoidType) {
           return relation.isVoidRelated(s, sNullability, t, tNullability, this);
         } else if (s is InterfaceType) {
-          return s.classNode == hierarchy.futureOrKernelClass
+          return s.classNode == hierarchy.futureOrClass
               ? relation.isFutureOrRelated(
                   s, sNullability, t, tNullability, this)
               : relation.isInterfaceRelated(
@@ -175,7 +175,7 @@
         } else if (s is VoidType) {
           return relation.isVoidRelated(s, sNullability, t, tNullability, this);
         } else if (s is InterfaceType) {
-          return s.classNode == hierarchy.futureOrKernelClass
+          return s.classNode == hierarchy.futureOrClass
               ? relation.isFutureOrRelated(
                   s, sNullability, t, tNullability, this)
               : relation.isInterfaceRelated(
@@ -202,7 +202,7 @@
       } else if (s is VoidType) {
         return relation.isVoidRelated(s, sNullability, t, tNullability, this);
       } else if (s is InterfaceType) {
-        return s.classNode == hierarchy.futureOrKernelClass
+        return s.classNode == hierarchy.futureOrClass
             ? relation.isFutureOrRelated(s, sNullability, t, tNullability, this)
             : relation.isInterfaceRelated(
                 s, sNullability, t, tNullability, this);
@@ -283,7 +283,7 @@
   @override
   bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
       InterfaceType t, Nullability tNullability, Types types) {
-    if (s.classNode == types.hierarchy.nullKernelClass) {
+    if (s.classNode == types.hierarchy.nullClass) {
       // This is an optimization, to avoid instantiating unnecessary type
       // arguments in getKernelTypeAsInstanceOf.
       return true;
@@ -316,7 +316,7 @@
       return false; // Rule 7.1
     }
     if (!types.isSubtypeOfKernel(
-        new InterfaceType(types.hierarchy.futureKernelClass, arguments), t)) {
+        new InterfaceType(types.hierarchy.futureClass, arguments), t)) {
       return false; // Rule 7.2
     }
     return true;
@@ -341,7 +341,7 @@
   @override
   bool isFunctionRelated(FunctionType s, Nullability sNullability,
       InterfaceType t, Nullability tNullability, Types types) {
-    return t.classNode == types.hierarchy.functionKernelClass; // Rule 14.
+    return t.classNode == types.hierarchy.functionClass; // Rule 14.
   }
 
   @override
@@ -443,7 +443,7 @@
   @override
   bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
       FunctionType t, Nullability tNullability, Types types) {
-    return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+    return s.classNode == types.hierarchy.nullClass; // Rule 4.
   }
 
   @override
@@ -518,7 +518,7 @@
   @override
   bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
       TypeParameterType t, Nullability tNullability, Types types) {
-    return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+    return s.classNode == types.hierarchy.nullClass; // Rule 4.
   }
 
   @override
@@ -628,7 +628,7 @@
     }
     // Rule 10.
     return types.isSubtypeOfKernel(
-        s, new InterfaceType(types.hierarchy.futureKernelClass, arguments));
+        s, new InterfaceType(types.hierarchy.futureClass, arguments));
   }
 
   @override
@@ -673,7 +673,7 @@
 
     // Rule 10.
     return types.isSubtypeOfKernel(
-        s, new InterfaceType(types.hierarchy.futureKernelClass, arguments));
+        s, new InterfaceType(types.hierarchy.futureClass, arguments));
   }
 
   @override
@@ -746,7 +746,7 @@
       TypeParameterType intersection,
       Nullability intersectionNullability,
       Types types) {
-    return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+    return s.classNode == types.hierarchy.nullClass; // Rule 4.
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/utils.dart b/pkg/front_end/lib/src/fasta/kernel/utils.dart
index 7f9f97d..8262018 100644
--- a/pkg/front_end/lib/src/fasta/kernel/utils.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/utils.dart
@@ -12,14 +12,15 @@
 
 import 'package:kernel/ast.dart'
     show
+        Class,
+        Component,
         DartType,
         Library,
-        Component,
         Procedure,
-        Class,
+        Supertype,
+        TreeNode,
         TypeParameter,
-        TypeParameterType,
-        Supertype;
+        TypeParameterType;
 
 import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
 
@@ -78,8 +79,11 @@
 const String kDebugClassName = "#DebugClass";
 
 Component createExpressionEvaluationComponent(Procedure procedure) {
-  Library fakeLibrary =
-      new Library(new Uri(scheme: 'evaluate', path: 'source'));
+  Library realLibrary = procedure.enclosingLibrary;
+
+  Library fakeLibrary = new Library(new Uri(scheme: 'evaluate', path: 'source'))
+    ..setLanguageVersion(
+        realLibrary.languageVersionMajor, realLibrary.languageVersionMinor);
 
   if (procedure.parent is Class) {
     Class realClass = procedure.parent;
@@ -98,7 +102,7 @@
         typeSubstitution: typeSubstitution, typeParams: typeParams);
 
     for (TypeParameter typeParam in realClass.typeParameters) {
-      fakeClass.typeParameters.add(typeParam.accept(cloner));
+      fakeClass.typeParameters.add(typeParam.accept<TreeNode>(cloner));
     }
 
     if (realClass.supertype != null) {
@@ -109,7 +113,7 @@
     }
 
     // Rebind the type parameters in the procedure.
-    procedure = procedure.accept(cloner);
+    procedure = procedure.accept<TreeNode>(cloner);
     procedure.parent = fakeClass;
     fakeClass.procedures.add(procedure);
     fakeLibrary.classes.add(fakeClass);
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index f24a1ce..ac24a09 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -9,6 +9,7 @@
         AsExpression,
         Class,
         Component,
+        DartType,
         ExpressionStatement,
         Field,
         Let,
@@ -32,7 +33,7 @@
 
 import '../severity.dart' show Severity;
 
-import '../type_inference/type_schema.dart' show TypeSchemaVisitor, UnknownType;
+import '../type_inference/type_schema.dart' show UnknownType;
 
 import 'kernel_shadow_ast.dart' show SyntheticExpressionJudgment;
 
@@ -47,8 +48,7 @@
   return verifier.errors;
 }
 
-class FastaVerifyingVisitor extends VerifyingVisitor
-    implements TypeSchemaVisitor<void> {
+class FastaVerifyingVisitor extends VerifyingVisitor {
   final List<LocatedMessage> errors = <LocatedMessage>[];
 
   Uri fileUri;
@@ -174,9 +174,12 @@
   }
 
   @override
-  visitUnknownType(UnknownType node) {
-    // Note: we can't pass [node] to [problem] because it's not a [TreeNode].
-    problem(null, "Unexpected appearance of the unknown type.");
+  defaultDartType(DartType node) {
+    if (node is UnknownType) {
+      // Note: we can't pass [node] to [problem] because it's not a [TreeNode].
+      problem(null, "Unexpected appearance of the unknown type.");
+    }
+    super.defaultDartType(node);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index b1ff995..7177fc3 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -11,10 +11,16 @@
 import 'package:kernel/ast.dart' show Class, DartType, Library;
 
 import 'builder/builder.dart'
-    show ClassBuilder, Builder, LibraryBuilder, TypeBuilder;
+    show Builder, ClassBuilder, LibraryBuilder, Scope, TypeBuilder;
+
+import 'builder/declaration_builder.dart' show DeclarationBuilder;
+
+import 'builder/modifier_builder.dart' show ModifierBuilder;
 
 import 'crash.dart' show firstSourceUri;
 
+import 'kernel/body_builder.dart' show BodyBuilder;
+
 import 'messages.dart'
     show
         FormattedMessage,
@@ -158,6 +164,11 @@
       }
       LibraryBuilder library =
           target.createLibraryBuilder(uri, fileUri, origin);
+      if (library == null) {
+        throw new StateError("createLibraryBuilder for uri $uri, "
+            "fileUri $fileUri returned null.");
+      }
+
       if (hasPackageSpecifiedLanguageVersion) {
         library.setLanguageVersion(packageSpecifiedLanguageVersionMajor,
             packageSpecifiedLanguageVersionMinor,
@@ -350,4 +361,14 @@
   ClassBuilder computeClassBuilderFromTargetClass(Class cls);
 
   TypeBuilder computeTypeBuilder(DartType type);
+
+  BodyBuilder createBodyBuilderForOutlineExpression(
+      LibraryBuilder library,
+      DeclarationBuilder declarationBuilder,
+      ModifierBuilder member,
+      Scope scope,
+      Uri fileUri) {
+    return new BodyBuilder.forOutlineExpression(
+        library, declarationBuilder, member, scope, fileUri);
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/parser.dart b/pkg/front_end/lib/src/fasta/parser.dart
index 0561820..950a70c 100644
--- a/pkg/front_end/lib/src/fasta/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser.dart
@@ -24,7 +24,7 @@
 
 export 'parser/listener.dart' show Listener;
 
-export 'parser/class_kind.dart' show ClassKind;
+export 'parser/declaration_kind.dart' show DeclarationKind;
 
 export 'parser/member_kind.dart' show MemberKind;
 
diff --git a/pkg/front_end/lib/src/fasta/parser/class_kind.dart b/pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
similarity index 70%
rename from pkg/front_end/lib/src/fasta/parser/class_kind.dart
rename to pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
index e5873ad..7037020 100644
--- a/pkg/front_end/lib/src/fasta/parser/class_kind.dart
+++ b/pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
@@ -1,10 +1,11 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library fasta.parser.class_kind;
+enum DeclarationKind {
+  /// A top level declaration.
+  TopLevel,
 
-enum ClassKind {
   /// A class declaration. Not including a named mixin declaration.
   Class,
 
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index ed2ea4e..e569a14 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -71,13 +71,13 @@
   }
 
   @override
-  void beginClassOrMixinBody(ClassKind kind, Token token) {
+  void beginClassOrMixinBody(DeclarationKind kind, Token token) {
     listener?.beginClassOrMixinBody(kind, token);
   }
 
   @override
-  void beginClassOrNamedMixinApplication(Token token) {
-    listener?.beginClassOrNamedMixinApplication(token);
+  void beginClassOrNamedMixinApplicationPrelude(Token token) {
+    listener?.beginClassOrNamedMixinApplicationPrelude(token);
   }
 
   @override
@@ -146,6 +146,11 @@
   }
 
   @override
+  void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+    listener?.beginExtensionDeclarationPrelude(extensionKeyword);
+  }
+
+  @override
   void beginExtensionDeclaration(Token extensionKeyword, Token name) {
     listener?.beginExtensionDeclaration(extensionKeyword, name);
   }
@@ -480,12 +485,6 @@
   }
 
   @override
-  void endInvalidAwaitExpression(
-      Token beginToken, Token endToken, MessageCode errorCode) {
-    listener?.endInvalidAwaitExpression(beginToken, endToken, errorCode);
-  }
-
-  @override
   void endBinaryExpression(Token token) {
     listener?.endBinaryExpression(token);
   }
@@ -516,13 +515,40 @@
   }
 
   @override
+  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    listener?.endClassConstructor(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endClassDeclaration(Token beginToken, Token endToken) {
     listener?.endClassDeclaration(beginToken, endToken);
   }
 
   @override
+  void endClassFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    listener?.endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    listener?.endClassFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    listener?.endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     listener?.endClassOrMixinBody(kind, memberCount, beginToken, endToken);
   }
 
@@ -594,15 +620,42 @@
   }
 
   @override
+  void endExtensionConstructor(Token getOrSet, Token beginToken,
+      Token beginParam, Token beginInitializers, Token endToken) {
+    listener?.endExtensionConstructor(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endExtensionDeclaration(
       Token extensionKeyword, Token onKeyword, Token token) {
     listener?.endExtensionDeclaration(extensionKeyword, onKeyword, token);
   }
 
   @override
-  void endFactoryMethod(
+  void endExtensionFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    listener?.endFactoryMethod(beginToken, factoryKeyword, endToken);
+    listener?.endExtensionFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endExtensionFields(
+      Token staticToken,
+      Token covariantToken,
+      Token lateToken,
+      Token varFinalOrConst,
+      int count,
+      Token beginToken,
+      Token endToken) {
+    listener?.endExtensionFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    listener?.endExtensionMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
 
   @override
@@ -611,13 +664,6 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
-      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
-    listener?.endFields(staticToken, covariantToken, lateToken, varFinalOrConst,
-        count, beginToken, endToken);
-  }
-
-  @override
   void endForControlFlow(Token token) {
     listener?.endForControlFlow(token);
   }
@@ -748,6 +794,12 @@
   }
 
   @override
+  void endInvalidAwaitExpression(
+      Token beginToken, Token endToken, MessageCode errorCode) {
+    listener?.endInvalidAwaitExpression(beginToken, endToken, errorCode);
+  }
+
+  @override
   void endLabeledStatement(int labelCount) {
     listener?.endLabeledStatement(labelCount);
   }
@@ -788,9 +840,9 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
-    listener?.endMethod(
+    listener?.endMixinConstructor(
         getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
 
@@ -800,6 +852,26 @@
   }
 
   @override
+  void endMixinFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    listener?.endMixinFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    listener?.endMixinFields(staticToken, covariantToken, lateToken,
+        varFinalOrConst, count, beginToken, endToken);
+  }
+
+  @override
+  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    listener?.endMixinMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endNamedFunctionExpression(Token endToken) {
     listener?.endNamedFunctionExpression(endToken);
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index 6312ccd..7d24308 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -19,7 +19,7 @@
 
 import 'identifier_context.dart' show IdentifierContext;
 
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
 
 import 'member_kind.dart' show MemberKind;
 
@@ -91,23 +91,28 @@
   /// Handle the start of the body of a class, mixin or extension declaration
   /// beginning at [token]. The actual kind of declaration is indicated by
   /// [kind].
-  void beginClassOrMixinBody(ClassKind kind, Token token) {}
+  void beginClassOrMixinBody(DeclarationKind kind, Token token) {}
 
   /// Handle the end of the body of a class, mixin or extension declaration.
   /// The only substructures are the class, mixin or extension members.
   ///
   /// The actual kind of declaration is indicated by [kind].
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     logEvent("ClassOrMixinBody");
   }
 
   /// Called before parsing a class or named mixin application.
-  void beginClassOrNamedMixinApplication(Token token) {}
+  ///
+  /// At this point only the `class` keyword have been seen, so we know a
+  /// declaration is coming but not its name or type parameter declarations.
+  void beginClassOrNamedMixinApplicationPrelude(Token token) {}
 
   /// Handle the beginning of a class declaration.
   /// [begin] may be the same as [name], or may point to modifiers
   /// (or extraneous modifiers in the case of recovery) preceding [name].
+  ///
+  /// At this point we have parsed the name and type parameter declarations.
   void beginClassDeclaration(Token begin, Token abstractToken, Token name) {}
 
   /// Handle an extends clause in a class declaration. Substructures:
@@ -195,7 +200,15 @@
 
   /// Handle the beginning of an extension methods declaration.  Substructures:
   /// - metadata
+  ///
+  /// At this point only the `extension` keyword have been seen, so we know a
+  /// declaration is coming but not its name or type parameter declarations.
+  void beginExtensionDeclarationPrelude(Token extensionKeyword) {}
+
+  /// Handle the beginning of an extension methods declaration.  Substructures:
   /// - type variables
+  ///
+  /// At this point we have parsed the name and type parameter declarations.
   void beginExtensionDeclaration(Token extensionKeyword, Token name) {}
 
   /// Handle the end of an extension methods declaration.  Substructures:
@@ -295,9 +308,21 @@
   void beginFactoryMethod(
       Token lastConsumed, Token externalToken, Token constToken) {}
 
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    logEvent("FactoryMethod");
+    logEvent("ClassFactoryMethod");
+  }
+
+  void endMixinFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  void endExtensionFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassFactoryMethod(beginToken, factoryKeyword, endToken);
   }
 
   void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
@@ -325,18 +350,52 @@
     logEvent("FormalParameters");
   }
 
-  /// Handle the end of a field declaration.  Substructures:
+  /// Handle the end of a class field declaration.  Substructures:
   /// - Metadata
   /// - Modifiers
   /// - Type
   /// - Variable declarations (count times)
   ///
   /// Doesn't have a corresponding begin event, use [beginMember] instead.
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     logEvent("Fields");
   }
 
+  /// Handle the end of a mixin field declaration.  Substructures:
+  /// - Metadata
+  /// - Modifiers
+  /// - Type
+  /// - Variable declarations (count times)
+  ///
+  /// Doesn't have a corresponding begin event, use [beginMember] instead.
+  void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+        count, beginToken, endToken);
+  }
+
+  /// Handle the end of a extension field declaration.  Substructures:
+  /// - Metadata
+  /// - Modifiers
+  /// - Type
+  /// - Variable declarations (count times)
+  ///
+  /// Doesn't have a corresponding begin event, use [beginMember] instead.
+  void endExtensionFields(
+      Token staticToken,
+      Token covariantToken,
+      Token lateToken,
+      Token varFinalOrConst,
+      int count,
+      Token beginToken,
+      Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+        count, beginToken, endToken);
+  }
+
   /// Marks that the grammar term `forInitializerStatement` has been parsed and
   /// it was an empty statement.
   void handleForInitializerEmptyStatement(Token token) {
@@ -514,6 +573,8 @@
   /// Handle the beginning of a named mixin application.
   /// [beginToken] may be the same as [name], or may point to modifiers
   /// (or extraneous modifiers in the case of recovery) preceding [name].
+  ///
+  /// At this point we have parsed the name and type parameter declarations.
   void beginNamedMixinApplication(
       Token begin, Token abstractToken, Token name) {}
 
@@ -749,7 +810,10 @@
   }
 
   /// This event is added for convenience. Normally, one should override
-  /// [endMethod] or [endFields] instead.
+  /// [endClassFields], [endMixinFields], [endExtensionFields],
+  /// [endClassMethod], [endMixinMethod], [endExtensionMethod],
+  /// [endClassConstructor], [endMixinConstructor],
+  /// or [endExtensionConstructor] instead.
   void endMember() {
     logEvent("Member");
   }
@@ -759,7 +823,7 @@
   void beginMethod(Token externalToken, Token staticToken, Token covariantToken,
       Token varFinalOrConst, Token getOrSet, Token name) {}
 
-  /// Handle the end of a method declaration.  Substructures:
+  /// Handle the end of a class method declaration.  Substructures:
   /// - metadata
   /// - return type
   /// - method name (identifier, possibly qualified)
@@ -768,9 +832,89 @@
   /// - initializers
   /// - async marker
   /// - body
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
-    logEvent("Method");
+    logEvent("ClassMethod");
+  }
+
+  /// Handle the end of a mixin method declaration.  Substructures:
+  /// - metadata
+  /// - return type
+  /// - method name (identifier, possibly qualified)
+  /// - type variables
+  /// - formal parameters
+  /// - initializers
+  /// - async marker
+  /// - body
+  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  /// Handle the end of a extension method declaration.  Substructures:
+  /// - metadata
+  /// - return type
+  /// - method name (identifier, possibly qualified)
+  /// - type variables
+  /// - formal parameters
+  /// - initializers
+  /// - async marker
+  /// - body
+  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  /// Handle the end of a class constructor declaration.  Substructures:
+  /// - metadata
+  /// - return type
+  /// - method name (identifier, possibly qualified)
+  /// - type variables
+  /// - formal parameters
+  /// - initializers
+  /// - async marker
+  /// - body
+  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  /// Handle the end of a mixin constructor declaration.  Substructures:
+  /// - metadata
+  /// - return type
+  /// - method name (identifier, possibly qualified)
+  /// - type variables
+  /// - formal parameters
+  /// - initializers
+  /// - async marker
+  /// - body
+  void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  /// Handle the end of a extension constructor declaration.  Substructures:
+  /// - metadata
+  /// - return type
+  /// - method name (identifier, possibly qualified)
+  /// - type variables
+  /// - formal parameters
+  /// - initializers
+  /// - async marker
+  /// - body
+  void endExtensionConstructor(Token getOrSet, Token beginToken,
+      Token beginParam, Token beginInitializers, Token endToken) {
+    // TODO(danrubel): push implementation into subclasses
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
   }
 
   void beginMetadataStar(Token token) {}
diff --git a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
index 5807629..2c11862 100644
--- a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
@@ -355,7 +355,7 @@
       if (constToken != null) {
         reportConflictingModifiers(next, constToken);
       } else if (varToken != null) {
-        reportConflictingModifiers(next, varToken);
+        reportModifierOutOfOrder(next, varToken.lexeme);
       } else if (finalToken != null) {
         reportModifierOutOfOrder(next, finalToken.lexeme);
       }
@@ -429,10 +429,6 @@
     assert(optional('var', next));
     if (varFinalOrConst == null && !afterFactory) {
       varToken = next;
-
-      if (lateToken != null) {
-        reportConflictingModifiers(next, lateToken);
-      }
       return next;
     }
 
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index affb84563..a296c652 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -53,7 +53,7 @@
 
 import 'async_modifier.dart' show AsyncModifier;
 
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
 
 import 'directive_context.dart';
 
@@ -127,7 +127,7 @@
 /// Parse methods all have the prefix `parse`, generate events
 /// (by calling methods on [listener]), and return the next token to parse.
 /// Some exceptions to this last point are methods such as [parseFunctionBody]
-/// and [parseClassOrMixinBody] which return the last token parsed
+/// and [parseClassOrMixinOrExtensionBody] which return the last token parsed
 /// rather than the next token to be parsed.
 /// Parse methods are generally named `parseGrammarProductionSuffix`.
 /// The suffix can be one of `opt`, or `star`.
@@ -1749,7 +1749,7 @@
       Token abstractToken, Token classKeyword) {
     assert(optional('class', classKeyword));
     Token begin = abstractToken ?? classKeyword;
-    listener.beginClassOrNamedMixinApplication(begin);
+    listener.beginClassOrNamedMixinApplicationPrelude(begin);
     Token name = ensureIdentifier(
         classKeyword, IdentifierContext.classOrMixinOrExtensionDeclaration);
     Token token = computeTypeParamOrArg(name, true).parseVariables(name, this);
@@ -1758,7 +1758,7 @@
       return parseNamedMixinApplication(token, begin, classKeyword);
     } else {
       listener.beginClassDeclaration(begin, abstractToken, name);
-      return parseClass(token, begin, classKeyword);
+      return parseClass(token, begin, classKeyword, name.lexeme);
     }
   }
 
@@ -1790,7 +1790,8 @@
   ///   metadata abstract? 'class' mixinApplicationClass
   /// ;
   /// ```
-  Token parseClass(Token token, Token begin, Token classKeyword) {
+  Token parseClass(
+      Token token, Token begin, Token classKeyword, String className) {
     Token start = token;
     token = parseClassHeaderOpt(token, begin, classKeyword);
     if (!optional('{', token.next)) {
@@ -1798,7 +1799,8 @@
       token = parseClassHeaderRecovery(start, begin, classKeyword);
       ensureBlock(token, null, 'class declaration');
     }
-    token = parseClassOrMixinBody(ClassKind.Class, token);
+    token = parseClassOrMixinOrExtensionBody(
+        token, DeclarationKind.Class, className);
     listener.endClassDeclaration(begin, token);
     return token;
   }
@@ -1953,7 +1955,7 @@
   /// ```
   Token parseMixin(Token mixinKeyword) {
     assert(optional('mixin', mixinKeyword));
-    listener.beginClassOrNamedMixinApplication(mixinKeyword);
+    listener.beginClassOrNamedMixinApplicationPrelude(mixinKeyword);
     Token name = ensureIdentifier(
         mixinKeyword, IdentifierContext.classOrMixinOrExtensionDeclaration);
     Token headerStart =
@@ -1965,7 +1967,8 @@
       token = parseMixinHeaderRecovery(token, mixinKeyword, headerStart);
       ensureBlock(token, null, 'mixin declaration');
     }
-    token = parseClassOrMixinBody(ClassKind.Mixin, token);
+    token = parseClassOrMixinOrExtensionBody(
+        token, DeclarationKind.Mixin, name.lexeme);
     listener.endMixinDeclaration(mixinKeyword, token);
     return token;
   }
@@ -2086,6 +2089,7 @@
   Token parseExtension(Token extensionKeyword) {
     assert(optional('extension', extensionKeyword));
     Token token = extensionKeyword;
+    listener.beginExtensionDeclarationPrelude(extensionKeyword);
     Token name = token.next;
     if (name.isIdentifier && !optional('on', name)) {
       token = name;
@@ -2134,8 +2138,8 @@
       }
       ensureBlock(token, null, 'extension declaration');
     }
-    // TODO(danrubel): Do not allow fields or constructors
-    token = parseClassOrMixinBody(ClassKind.Extension, token);
+    token = parseClassOrMixinOrExtensionBody(
+        token, DeclarationKind.Extension, name?.lexeme);
     listener.endExtensionDeclaration(extensionKeyword, onKeyword, token);
     return token;
   }
@@ -2351,8 +2355,17 @@
       reportRecoverableErrorWithToken(
           getOrSet, fasta.templateExtraneousModifier);
     }
-    return parseFields(beforeStart, externalToken, null, null, lateToken,
-        varFinalOrConst, beforeType, typeInfo, token.next, true);
+    return parseFields(
+        beforeStart,
+        externalToken,
+        null,
+        null,
+        lateToken,
+        varFinalOrConst,
+        beforeType,
+        typeInfo,
+        token.next,
+        DeclarationKind.TopLevel);
   }
 
   Token parseFields(
@@ -2365,7 +2378,7 @@
       Token beforeType,
       TypeInfo typeInfo,
       Token name,
-      bool isTopLevel) {
+      DeclarationKind kind) {
     if (externalToken != null) {
       reportRecoverableError(externalToken, fasta.messageExternalField);
     }
@@ -2388,18 +2401,18 @@
     Token token = typeInfo.parseType(beforeType, this);
     assert(token.next == name);
 
-    IdentifierContext context = isTopLevel
+    IdentifierContext context = kind == DeclarationKind.TopLevel
         ? IdentifierContext.topLevelVariableDeclaration
         : IdentifierContext.fieldDeclaration;
-    name = ensureIdentifier(token, context);
+    Token firstName = name = ensureIdentifier(token, context);
 
     int fieldCount = 1;
-    token = parseFieldInitializerOpt(
-        name, name, lateToken, varFinalOrConst, isTopLevel);
+    token =
+        parseFieldInitializerOpt(name, name, lateToken, varFinalOrConst, kind);
     while (optional(',', token.next)) {
       name = ensureIdentifier(token.next, context);
       token = parseFieldInitializerOpt(
-          name, name, lateToken, varFinalOrConst, isTopLevel);
+          name, name, lateToken, varFinalOrConst, kind);
       ++fieldCount;
     }
     Token semicolon = token.next;
@@ -2407,7 +2420,7 @@
       token = semicolon;
     } else {
       // Recovery
-      if (isTopLevel &&
+      if (kind == DeclarationKind.TopLevel &&
           beforeType.next.isIdentifier &&
           beforeType.next.lexeme == 'extension') {
         // Looks like an extension method
@@ -2423,12 +2436,27 @@
         token = ensureSemicolon(token);
       }
     }
-    if (isTopLevel) {
-      listener.endTopLevelFields(staticToken, covariantToken, lateToken,
-          varFinalOrConst, fieldCount, beforeStart.next, token);
-    } else {
-      listener.endFields(staticToken, covariantToken, lateToken,
-          varFinalOrConst, fieldCount, beforeStart.next, token);
+    switch (kind) {
+      case DeclarationKind.TopLevel:
+        listener.endTopLevelFields(staticToken, covariantToken, lateToken,
+            varFinalOrConst, fieldCount, beforeStart.next, token);
+        break;
+      case DeclarationKind.Class:
+        listener.endClassFields(staticToken, covariantToken, lateToken,
+            varFinalOrConst, fieldCount, beforeStart.next, token);
+        break;
+      case DeclarationKind.Mixin:
+        listener.endMixinFields(staticToken, covariantToken, lateToken,
+            varFinalOrConst, fieldCount, beforeStart.next, token);
+        break;
+      case DeclarationKind.Extension:
+        if (staticToken == null) {
+          reportRecoverableError(
+              firstName, fasta.messageExtensionDeclaresInstanceField);
+        }
+        listener.endExtensionFields(staticToken, covariantToken, lateToken,
+            varFinalOrConst, fieldCount, beforeStart.next, token);
+        break;
     }
     return token;
   }
@@ -2484,7 +2512,7 @@
   }
 
   Token parseFieldInitializerOpt(Token token, Token name, Token lateToken,
-      Token varFinalOrConst, bool isTopLevel) {
+      Token varFinalOrConst, DeclarationKind kind) {
     Token next = token.next;
     if (optional('=', next)) {
       Token assignment = next;
@@ -2498,7 +2526,7 @@
               name,
               fasta.templateConstFieldWithoutInitializer
                   .withArguments(name.lexeme));
-        } else if (isTopLevel &&
+        } else if (kind == DeclarationKind.TopLevel &&
             optional("final", varFinalOrConst) &&
             lateToken == null) {
           reportRecoverableError(
@@ -2893,7 +2921,7 @@
     return token;
   }
 
-  Token skipClassOrMixinBody(Token token) {
+  Token skipClassOrMixinOrExtensionBody(Token token) {
     // The scanner ensures that `{` always has a closing `}`.
     return ensureBlock(token, null, null);
   }
@@ -2903,13 +2931,15 @@
   ///   '{' classMember* '}'
   /// ;
   /// ```
-  Token parseClassOrMixinBody(ClassKind kind, Token token) {
+  Token parseClassOrMixinOrExtensionBody(
+      Token token, DeclarationKind kind, String enclosingDeclarationName) {
     Token begin = token = token.next;
     assert(optional('{', token));
     listener.beginClassOrMixinBody(kind, token);
     int count = 0;
     while (notEofOrValue('}', token.next)) {
-      token = parseClassOrMixinMemberImpl(token);
+      token = parseClassOrMixinOrExtensionMemberImpl(
+          token, kind, enclosingDeclarationName);
       ++count;
     }
     token = token.next;
@@ -2923,14 +2953,40 @@
       token.lexeme == 'unary' &&
       optional('-', token.next);
 
-  /// Parse a class or mixin member.
+  /// Parse a class member.
   ///
   /// This method is only invoked from outside the parser. As a result, this
   /// method takes the next token to be consumed rather than the last consumed
   /// token and returns the token after the last consumed token rather than the
   /// last consumed token.
-  Token parseClassOrMixinMember(Token token) {
-    return parseClassOrMixinMemberImpl(syntheticPreviousToken(token)).next;
+  Token parseClassMember(Token token, String className) {
+    return parseClassOrMixinOrExtensionMemberImpl(
+            syntheticPreviousToken(token), DeclarationKind.Class, className)
+        .next;
+  }
+
+  /// Parse a mixin member.
+  ///
+  /// This method is only invoked from outside the parser. As a result, this
+  /// method takes the next token to be consumed rather than the last consumed
+  /// token and returns the token after the last consumed token rather than the
+  /// last consumed token.
+  Token parseMixinMember(Token token, String mixinName) {
+    return parseClassOrMixinOrExtensionMemberImpl(
+            syntheticPreviousToken(token), DeclarationKind.Mixin, mixinName)
+        .next;
+  }
+
+  /// Parse an extension member.
+  ///
+  /// This method is only invoked from outside the parser. As a result, this
+  /// method takes the next token to be consumed rather than the last consumed
+  /// token and returns the token after the last consumed token rather than the
+  /// last consumed token.
+  Token parseExtensionMember(Token token, String extensionName) {
+    return parseClassOrMixinOrExtensionMemberImpl(syntheticPreviousToken(token),
+            DeclarationKind.Extension, extensionName)
+        .next;
   }
 
   /// ```
@@ -2944,8 +3000,14 @@
   ///   fieldDeclaration |
   ///   methodDeclaration
   /// ;
+  ///
+  /// extensionMember:
+  ///   staticFieldDeclaration |
+  ///   methodDeclaration
+  /// ;
   /// ```
-  Token parseClassOrMixinMemberImpl(Token token) {
+  Token parseClassOrMixinOrExtensionMemberImpl(
+      Token token, DeclarationKind kind, String enclosingDeclarationName) {
     Token beforeStart = token = parseMetadataStar(token);
 
     Token covariantToken;
@@ -3031,7 +3093,7 @@
           if (beforeType != token) {
             reportRecoverableError(token, fasta.messageTypeBeforeFactory);
           }
-          token = parseFactoryMethod(token, beforeStart, externalToken,
+          token = parseFactoryMethod(token, kind, beforeStart, externalToken,
               staticToken ?? covariantToken, varFinalOrConst);
           listener.endMember();
           return token;
@@ -3053,7 +3115,9 @@
               beforeType,
               typeInfo,
               getOrSet,
-              token.next);
+              token.next,
+              kind,
+              enclosingDeclarationName);
           listener.endMember();
           return token;
         } else if (optional('===', next2) ||
@@ -3069,7 +3133,8 @@
               covariantToken,
               lateToken,
               varFinalOrConst,
-              beforeType);
+              beforeType,
+              kind);
         } else if (isUnaryMinus(next2)) {
           // Recovery
           token = parseMethod(
@@ -3082,7 +3147,9 @@
               beforeType,
               typeInfo,
               getOrSet,
-              token.next);
+              token.next,
+              kind,
+              enclosingDeclarationName);
           listener.endMember();
           return token;
         }
@@ -3092,7 +3159,7 @@
               token == beforeStart &&
               next.next.isIdentifier)) {
         // Recovery
-        return recoverFromInvalidClassMember(
+        return recoverFromInvalidMember(
             token,
             beforeStart,
             externalToken,
@@ -3102,7 +3169,9 @@
             varFinalOrConst,
             beforeType,
             typeInfo,
-            getOrSet);
+            getOrSet,
+            kind,
+            enclosingDeclarationName);
       }
     } else if (typeInfo == noType && varFinalOrConst == null) {
       Token next2 = next.next;
@@ -3119,7 +3188,8 @@
               covariantToken,
               lateToken,
               varFinalOrConst,
-              beforeType);
+              beforeType,
+              kind);
         }
       }
     }
@@ -3143,7 +3213,9 @@
           beforeType,
           typeInfo,
           getOrSet,
-          token.next);
+          token.next,
+          kind,
+          enclosingDeclarationName);
     } else {
       if (getOrSet != null) {
         reportRecoverableErrorWithToken(
@@ -3159,7 +3231,7 @@
           beforeType,
           typeInfo,
           token.next,
-          false);
+          kind);
     }
     listener.endMember();
     return token;
@@ -3175,7 +3247,9 @@
       Token beforeType,
       TypeInfo typeInfo,
       Token getOrSet,
-      Token name) {
+      Token name,
+      DeclarationKind kind,
+      String enclosingDeclarationName) {
     if (lateToken != null) {
       reportRecoverableErrorWithToken(
           lateToken, fasta.templateExtraneousModifier);
@@ -3247,12 +3321,14 @@
       listener.handleNoTypeVariables(token.next);
     }
 
-    MemberKind kind = staticToken != null
-        ? MemberKind.StaticMethod
-        : MemberKind.NonStaticMethod;
     Token beforeParam = token;
-    Token beforeInitializers =
-        parseGetterOrFormalParameters(token, name, isGetter, kind);
+    Token beforeInitializers = parseGetterOrFormalParameters(
+        token,
+        name,
+        isGetter,
+        staticToken != null
+            ? MemberKind.StaticMethod
+            : MemberKind.NonStaticMethod);
     token = parseInitializersOpt(beforeInitializers);
     if (token == beforeInitializers) beforeInitializers = null;
 
@@ -3262,27 +3338,124 @@
     if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
       reportRecoverableError(asyncToken, fasta.messageSetterNotSync);
     }
-    Token next = token.next;
+    final Token bodyStart = token.next;
     if (externalToken != null) {
-      if (!optional(';', next)) {
-        reportRecoverableError(next, fasta.messageExternalMethodWithBody);
+      if (!optional(';', bodyStart)) {
+        reportRecoverableError(bodyStart, fasta.messageExternalMethodWithBody);
       }
     }
-    if (optional('=', next)) {
-      reportRecoverableError(next, fasta.messageRedirectionInNonFactory);
+    if (optional('=', bodyStart)) {
+      reportRecoverableError(bodyStart, fasta.messageRedirectionInNonFactory);
       token = parseRedirectingFactoryBody(token);
     } else {
       token = parseFunctionBody(token, false,
           (staticToken == null || externalToken != null) && inPlainSync);
     }
     asyncState = savedAsyncModifier;
-    listener.endMethod(getOrSet, beforeStart.next, beforeParam.next,
-        beforeInitializers?.next, token);
+
+    bool isConstructor = false;
+    if (optional('.', name.next) || beforeInitializers != null) {
+      isConstructor = true;
+      if (name.lexeme != enclosingDeclarationName) {
+        // Recovery: The name does not match,
+        // but the name is prefixed or the declaration contains initializers.
+        // Report an error and continue with invalid name.
+        // TODO(danrubel): report invalid constructor name
+        // Currently multiple listeners report this error, but that logic should
+        // be removed and the error reported here instead.
+      }
+      if (getOrSet != null) {
+        // Recovery
+        if (optional('.', name.next)) {
+          // Unexpected get/set before constructor.
+          // Report an error and skip over the token.
+          // TODO(danrubel): report an error on get/set token
+          // This is currently reported by listeners other than AstBuilder.
+          // It should be reported here rather than in the listeners.
+        } else {
+          isConstructor = false;
+          if (beforeInitializers != null) {
+            // Unexpected initializers after get/set declaration.
+            // Report an error on the initializers
+            // and continue with the get/set declaration.
+            // TODO(danrubel): report invalid initializers error
+            // Currently multiple listeners report this error, but that logic
+            // should be removed and the error reported here instead.
+          }
+        }
+      }
+    } else if (name.lexeme == enclosingDeclarationName) {
+      if (getOrSet != null) {
+        // Recovery: The get/set member name is invalid.
+        // Report an error and continue with invalid name.
+        // TODO(danrubel): report invalid get/set member name
+        // Currently multiple listeners report this error, but that logic should
+        // be removed and the error reported here instead.
+      } else {
+        isConstructor = true;
+      }
+    }
+
+    if (isConstructor) {
+      //
+      // constructor
+      //
+      if (staticToken != null) {
+        reportRecoverableError(staticToken, fasta.messageStaticConstructor);
+      }
+      switch (kind) {
+        case DeclarationKind.Class:
+          // TODO(danrubel): Remove getOrSet from constructor events
+          listener.endClassConstructor(getOrSet, beforeStart.next,
+              beforeParam.next, beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.Mixin:
+          reportRecoverableError(name, fasta.messageMixinDeclaresConstructor);
+          listener.endMixinConstructor(getOrSet, beforeStart.next,
+              beforeParam.next, beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.Extension:
+          reportRecoverableError(
+              name, fasta.messageExtensionDeclaresConstructor);
+          listener.endExtensionConstructor(getOrSet, beforeStart.next,
+              beforeParam.next, beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.TopLevel:
+          throw "Internal error: TopLevel constructor.";
+          break;
+      }
+    } else {
+      //
+      // method
+      //
+      switch (kind) {
+        case DeclarationKind.Class:
+          // TODO(danrubel): Remove beginInitializers token from method events
+          listener.endClassMethod(getOrSet, beforeStart.next, beforeParam.next,
+              beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.Mixin:
+          listener.endMixinMethod(getOrSet, beforeStart.next, beforeParam.next,
+              beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.Extension:
+          if (optional(';', bodyStart)) {
+            reportRecoverableError(isOperator ? name.next : name,
+                fasta.messageExtensionDeclaresAbstractMember);
+          }
+          listener.endExtensionMethod(getOrSet, beforeStart.next,
+              beforeParam.next, beforeInitializers?.next, token);
+          break;
+        case DeclarationKind.TopLevel:
+          throw "Internal error: TopLevel method.";
+          break;
+      }
+    }
     return token;
   }
 
-  Token parseFactoryMethod(Token token, Token beforeStart, Token externalToken,
-      Token staticOrCovariant, Token varFinalOrConst) {
+  Token parseFactoryMethod(Token token, DeclarationKind kind, Token beforeStart,
+      Token externalToken, Token staticOrCovariant, Token varFinalOrConst) {
     Token factoryKeyword = token = token.next;
     assert(optional('factory', factoryKeyword));
 
@@ -3342,7 +3515,25 @@
       }
       token = parseFunctionBody(token, false, false);
     }
-    listener.endFactoryMethod(beforeStart.next, factoryKeyword, token);
+    switch (kind) {
+      case DeclarationKind.Class:
+        listener.endClassFactoryMethod(beforeStart.next, factoryKeyword, token);
+        break;
+      case DeclarationKind.Mixin:
+        reportRecoverableError(
+            factoryKeyword, fasta.messageMixinDeclaresConstructor);
+        listener.endMixinFactoryMethod(beforeStart.next, factoryKeyword, token);
+        break;
+      case DeclarationKind.Extension:
+        reportRecoverableError(
+            factoryKeyword, fasta.messageExtensionDeclaresConstructor);
+        listener.endExtensionFactoryMethod(
+            beforeStart.next, factoryKeyword, token);
+        break;
+      case DeclarationKind.TopLevel:
+        throw "Internal error: TopLevel factory.";
+        break;
+    }
     return token;
   }
 
@@ -4008,7 +4199,7 @@
             listener.handleUnaryPostfixAssignmentExpression(token.next);
             token = next;
           } else if (identical(type, TokenType.BANG)) {
-            listener.handleNonNullAssertExpression(token.next);
+            listener.handleNonNullAssertExpression(next);
             token = next;
           }
         } else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
@@ -4081,7 +4272,10 @@
     if (identical(type, TokenType.BANG)) {
       // The '!' has prefix precedence but here it's being used as a
       // postfix operator to assert the expression has a non-null value.
-      if (identical(token.next.type, TokenType.PERIOD)) {
+      TokenType nextType = token.next.type;
+      if (identical(nextType, TokenType.PERIOD) ||
+          identical(nextType, TokenType.OPEN_PAREN) ||
+          identical(nextType, TokenType.OPEN_SQUARE_BRACKET)) {
         return SELECTOR_PRECEDENCE;
       }
       return POSTFIX_PRECEDENCE;
@@ -5208,7 +5402,8 @@
       } else if (optional('late', next)) {
         lateToken = token = next;
         next = token.next;
-        if (isModifier(next) && optional('final', next)) {
+        if (isModifier(next) &&
+            (optional('var', next) || optional('final', next))) {
           varFinalOrConst = token = next;
           next = token.next;
         }
@@ -5278,7 +5473,12 @@
         typeInfo.isNullable &&
         typeInfo.couldBeExpression) {
       assert(optional('?', token));
-      assert(next.isIdentifier);
+      assert(next.isKeywordOrIdentifier);
+      if (!next.isIdentifier) {
+        reportRecoverableError(
+            next, fasta.templateExpectedIdentifier.withArguments(next));
+        next = rewriter.insertSyntheticIdentifier(next);
+      }
       Token afterIdentifier = next.next;
       //
       // found <typeref> `?` <identifier>
@@ -6255,7 +6455,8 @@
       Token covariantToken,
       Token lateToken,
       Token varFinalOrConst,
-      Token beforeType) {
+      Token beforeType,
+      DeclarationKind kind) {
     TypeInfo typeInfo = computeType(beforeType, true, true);
 
     Token beforeName = typeInfo.skipType(beforeType);
@@ -6282,7 +6483,9 @@
         beforeType,
         typeInfo,
         null,
-        beforeName.next);
+        beforeName.next,
+        kind,
+        null);
     listener.endMember();
     return token;
   }
@@ -6290,7 +6493,7 @@
   /// Recover from finding an invalid class member. The metadata for the member,
   /// if any, has already been parsed (and events have already been generated).
   /// The member was expected to start with the token after [token].
-  Token recoverFromInvalidClassMember(
+  Token recoverFromInvalidMember(
       Token token,
       Token beforeStart,
       Token externalToken,
@@ -6300,7 +6503,9 @@
       Token varFinalOrConst,
       Token beforeType,
       TypeInfo typeInfo,
-      Token getOrSet) {
+      Token getOrSet,
+      DeclarationKind kind,
+      String enclosingDeclarationName) {
     Token next = token.next;
     String value = next.stringValue;
 
@@ -6311,8 +6516,15 @@
     } else if (identical(value, 'typedef')) {
       return reportAndSkipTypedefInClass(next);
     } else if (next.isOperator && next.endGroup == null) {
-      return parseInvalidOperatorDeclaration(beforeStart, externalToken,
-          staticToken, covariantToken, lateToken, varFinalOrConst, beforeType);
+      return parseInvalidOperatorDeclaration(
+          beforeStart,
+          externalToken,
+          staticToken,
+          covariantToken,
+          lateToken,
+          varFinalOrConst,
+          beforeType,
+          kind);
     }
 
     if (getOrSet != null ||
@@ -6329,7 +6541,9 @@
           beforeType,
           typeInfo,
           getOrSet,
-          token.next);
+          token.next,
+          kind,
+          enclosingDeclarationName);
     } else if (token == beforeStart) {
       // TODO(danrubel): Provide a more specific error message for extra ';'.
       reportRecoverableErrorWithToken(next, fasta.templateExpectedClassMember);
@@ -6349,7 +6563,7 @@
           beforeType,
           typeInfo,
           token.next,
-          false);
+          kind);
     }
 
     listener.endMember();
diff --git a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
index e75ccc9..802f28e 100644
--- a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
@@ -6,7 +6,7 @@
 
 import '../../scanner/token.dart' show Token;
 
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
 
 import 'class_member_parser.dart' show ClassMemberParser;
 
@@ -17,6 +17,8 @@
 class TopLevelParser extends ClassMemberParser {
   TopLevelParser(Listener listener) : super(listener);
 
-  Token parseClassOrMixinBody(ClassKind kind, Token token) =>
-      skipClassOrMixinBody(token);
+  @override
+  Token parseClassOrMixinOrExtensionBody(
+          Token token, DeclarationKind kind, String enclosingDeclarationName) =>
+      skipClassOrMixinOrExtensionBody(token);
 }
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 2103911..50fedf3 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -1350,7 +1350,7 @@
     while (true) {
       if (identical($EOF, next)) {
         if (!asciiOnlyLines) handleUnicode(unicodeStart);
-        prependErrorToken(UnterminatedToken(
+        prependErrorToken(new UnterminatedToken(
             messageUnterminatedComment, tokenStart, stringOffset));
         advanceAfterError(true);
         break;
@@ -1618,7 +1618,7 @@
     } else {
       beginToken(); // The synthetic identifier starts here.
       appendSyntheticSubstringToken(TokenType.IDENTIFIER, scanOffset, true, '');
-      prependErrorToken(UnterminatedToken(
+      prependErrorToken(new UnterminatedToken(
           messageUnexpectedDollarInString, tokenStart, stringOffset));
     }
     beginToken(); // The string interpolation suffix starts here.
@@ -1763,7 +1763,7 @@
         codeUnits.add(next);
         next = advance();
       }
-      appendToken(StringToken.fromString(TokenType.IDENTIFIER,
+      appendToken(new StringToken.fromString(TokenType.IDENTIFIER,
           new String.fromCharCodes(codeUnits), charOffset));
       return next;
     } else {
@@ -1885,9 +1885,9 @@
 /// [ScannerConfiguration] contains information for configuring which tokens
 /// the scanner produces based upon the Dart language level.
 class ScannerConfiguration {
-  static const ScannerConfiguration classic = ScannerConfiguration();
+  static const ScannerConfiguration classic = const ScannerConfiguration();
   static const ScannerConfiguration nonNullable =
-      ScannerConfiguration(enableNonNullable: true);
+      const ScannerConfiguration(enableNonNullable: true);
 
   /// Experimental flag for enabling scanning of the `extension` keyword.
   final bool enableExtensionMethods;
diff --git a/pkg/front_end/lib/src/fasta/scanner/error_token.dart b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
index 7c4ba8a..57a5e0f 100644
--- a/pkg/front_end/lib/src/fasta/scanner/error_token.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
@@ -77,7 +77,7 @@
 
     // Attempt to include the location which is calling the parser
     // in an effort to debug https://github.com/dart-lang/sdk/issues/37528
-    RegExp pattern = RegExp('^#[0-9]* *Parser');
+    RegExp pattern = new RegExp('^#[0-9]* *Parser');
     List<String> traceLines = StackTrace.current.toString().split('\n');
     for (int index = traceLines.length - 2; index >= 0; --index) {
       String line = traceLines[index];
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 40ca796..404a00e 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -6,6 +6,8 @@
 
 import 'builder/builder.dart' show Builder, NameIterator, TypeVariableBuilder;
 
+import 'builder/extension_builder.dart';
+
 import 'fasta_codes.dart'
     show
         LocatedMessage,
@@ -24,14 +26,45 @@
   /// Setters declared in this scope.
   Map<String, Builder> setters;
 
+  /// The extensions declared in this scope.
+  ///
+  /// This includes all available extensions even if the extensions are not
+  /// accessible by name because of duplicate imports.
+  ///
+  /// For instance:
+  ///
+  ///   lib1.dart:
+  ///     extension Extension on String {
+  ///       method1() {}
+  ///       staticMethod1() {}
+  ///     }
+  ///   lib2.dart:
+  ///     extension Extension on String {
+  ///       method2() {}
+  ///       staticMethod2() {}
+  ///     }
+  ///   main.dart:
+  ///     import 'lib1.dart';
+  ///     import 'lib2.dart';
+  ///
+  ///     main() {
+  ///       'foo'.method1(); // This method is available.
+  ///       'foo'.method2(); // This method is available.
+  ///       // These methods are not available because Extension is ambiguous:
+  ///       Extension.staticMethod1();
+  ///       Extension.staticMethod2();
+  ///     }
+  ///
+  List<ExtensionBuilder> _extensions;
+
   /// The scope that this scope is nested within, or `null` if this is the top
   /// level scope.
   Scope parent;
 
   final String classNameOrDebugName;
 
-  MutableScope(
-      this.local, this.setters, this.parent, this.classNameOrDebugName) {
+  MutableScope(this.local, this.setters, this._extensions, this.parent,
+      this.classNameOrDebugName) {
     assert(classNameOrDebugName != null);
   }
 
@@ -49,22 +82,36 @@
 
   Map<String, int> usedNames;
 
-  Scope(Map<String, Builder> local, Map<String, Builder> setters, Scope parent,
-      String debugName, {this.isModifiable: true})
-      : super(local, setters = setters ?? const <String, Builder>{}, parent,
-            debugName);
+  Scope(
+      {Map<String, Builder> local,
+      Map<String, Builder> setters,
+      List<ExtensionBuilder> extensions,
+      Scope parent,
+      String debugName,
+      this.isModifiable: true})
+      : super(local, setters = setters ?? const <String, Builder>{}, extensions,
+            parent, debugName);
 
   Scope.top({bool isModifiable: false})
-      : this(<String, Builder>{}, <String, Builder>{}, null, "top",
+      : this(
+            local: <String, Builder>{},
+            setters: <String, Builder>{},
+            debugName: "top",
             isModifiable: isModifiable);
 
   Scope.immutable()
-      : this(const <String, Builder>{}, const <String, Builder>{}, null,
-            "immutable",
+      : this(
+            local: const <String, Builder>{},
+            setters: const <String, Builder>{},
+            debugName: "immutable",
             isModifiable: false);
 
   Scope.nested(Scope parent, String debugName, {bool isModifiable: true})
-      : this(<String, Builder>{}, <String, Builder>{}, parent, debugName,
+      : this(
+            local: <String, Builder>{},
+            setters: <String, Builder>{},
+            parent: parent,
+            debugName: debugName,
             isModifiable: isModifiable);
 
   Iterator<Builder> get iterator {
@@ -76,7 +123,12 @@
   }
 
   Scope copyWithParent(Scope parent, String debugName) {
-    return new Scope(super.local, super.setters, parent, debugName,
+    return new Scope(
+        local: super.local,
+        setters: super.setters,
+        extensions: _extensions,
+        parent: parent,
+        debugName: debugName,
         isModifiable: isModifiable);
   }
 
@@ -97,6 +149,7 @@
     super.local = scope.local;
     super.setters = scope.setters;
     super.parent = scope.parent;
+    super._extensions = scope._extensions;
   }
 
   Scope createNestedScope(String debugName, {bool isModifiable: true}) {
@@ -121,7 +174,13 @@
   ///     x = 42;
   ///     print("The answer is $x.");
   Scope createNestedLabelScope() {
-    return new Scope(local, setters, parent, "label", isModifiable: true);
+    return new Scope(
+        local: local,
+        setters: setters,
+        extensions: _extensions,
+        parent: parent,
+        debugName: "label",
+        isModifiable: true);
   }
 
   void recordUse(String name, int charOffset, Uri fileUri) {
@@ -235,6 +294,18 @@
     return null;
   }
 
+  /// Adds [builder] to the extensions in this scope.
+  void addExtension(ExtensionBuilder builder) {
+    _extensions ??= [];
+    _extensions.add(builder);
+  }
+
+  /// Calls [f] for each extension in this scope and parent scopes.
+  void forEachExtension(void Function(ExtensionBuilder) f) {
+    _extensions?.forEach(f);
+    parent?.forEachExtension(f);
+  }
+
   void merge(
       Scope scope,
       Builder computeAmbiguousDeclaration(
@@ -308,7 +379,12 @@
       }
     }
     return needsCopy
-        ? new Scope(local, setters, parent, classNameOrDebugName,
+        ? new Scope(
+            local: local,
+            setters: setters,
+            extensions: _extensions,
+            parent: parent,
+            debugName: classNameOrDebugName,
             isModifiable: isModifiable)
         : this;
   }
@@ -327,6 +403,10 @@
     scope.setters[name] = builder;
   }
 
+  void addExtension(ExtensionBuilder builder) {
+    scope.addExtension(builder);
+  }
+
   Builder operator [](String name) => scope.local[name];
 }
 
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 69f967d..b855f5b 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -45,7 +45,8 @@
 import '../kernel/kernel_builder.dart'
     show FormalParameterBuilder, TypeAliasBuilder, TypeBuilder;
 
-import '../parser.dart' show Assert, ClassKind, MemberKind, Parser, optional;
+import '../parser.dart'
+    show Assert, DeclarationKind, MemberKind, Parser, optional;
 
 import '../problems.dart'
     show DebugAbort, internalProblem, unexpected, unhandled;
@@ -64,7 +65,7 @@
 import '../quote.dart' show unescapeString;
 
 class DietListener extends StackListener {
-  final SourceLibraryBuilder library;
+  final SourceLibraryBuilder libraryBuilder;
 
   final ClassHierarchy hierarchy;
 
@@ -96,7 +97,7 @@
 
   DietListener(SourceLibraryBuilder library, this.hierarchy, this.coreTypes,
       this.typeInferenceEngine)
-      : library = library,
+      : libraryBuilder = library,
         uri = library.fileUri,
         memberScope = library.scope,
         enableNative =
@@ -262,8 +263,8 @@
     checkEmpty(typedefKeyword.charOffset);
     if (name is ParserRecovery) return;
 
-    Builder typedefBuilder = lookupBuilder(typedefKeyword, null, name);
-    parseMetadata(typedefBuilder, metadata, typedefBuilder.target);
+    TypeAliasBuilder typedefBuilder = lookupBuilder(typedefKeyword, null, name);
+    parseMetadata(typedefBuilder, metadata, typedefBuilder.typedef);
     if (typedefBuilder is TypeAliasBuilder) {
       TypeBuilder type = typedefBuilder.type;
       if (type is FunctionTypeBuilder) {
@@ -281,13 +282,13 @@
                   parseMetadata(typedefBuilder, metadataToken, null);
               if (formal.isPositional) {
                 VariableDeclaration parameter =
-                    typedefBuilder.target.positionalParameters[i];
+                    typedefBuilder.typedef.positionalParameters[i];
                 for (Expression annotation in annotations) {
                   parameter.addAnnotation(annotation);
                 }
               } else {
                 for (VariableDeclaration named
-                    in typedefBuilder.target.namedParameters) {
+                    in typedefBuilder.typedef.namedParameters) {
                   if (named.name == formal.name) {
                     for (Expression annotation in annotations) {
                       named.addAnnotation(annotation);
@@ -308,7 +309,7 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     debugEvent("Fields");
     buildFields(count, beginToken, false);
@@ -498,10 +499,10 @@
         unescapeString(importUriToken.lexeme, importUriToken, this);
     if (importUri.startsWith("dart-ext:")) return;
 
-    Library libraryNode = library.target;
+    Library libraryNode = libraryBuilder.library;
     LibraryDependency dependency =
         libraryNode.dependencies[importExportDirectiveIndex++];
-    parseMetadata(library, metadata, dependency);
+    parseMetadata(libraryBuilder, metadata, dependency);
   }
 
   @override
@@ -514,10 +515,10 @@
     debugEvent("Export");
 
     Token metadata = pop();
-    Library libraryNode = library.target;
+    Library libraryNode = libraryBuilder.library;
     LibraryDependency dependency =
         libraryNode.dependencies[importExportDirectiveIndex++];
-    parseMetadata(library, metadata, dependency);
+    parseMetadata(libraryBuilder, metadata, dependency);
   }
 
   @override
@@ -525,14 +526,14 @@
     debugEvent("Part");
 
     Token metadata = pop();
-    Library libraryNode = library.target;
+    Library libraryNode = libraryBuilder.library;
     if (libraryNode.parts.length > partDirectiveIndex) {
       // If partDirectiveIndex >= libraryNode.parts.length we are in a case of
       // on part having other parts. An error has already been issued.
       // Don't try to parse metadata into other parts that have nothing to do
       // with the one this keyword is talking about.
       LibraryPart part = libraryNode.parts[partDirectiveIndex++];
-      parseMetadata(library, metadata, part);
+      parseMetadata(libraryBuilder, metadata, part);
     }
   }
 
@@ -560,9 +561,9 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    debugEvent("FactoryMethod");
+    debugEvent("ClassFactoryMethod");
     Token bodyToken = pop();
     Object name = pop();
     Token metadata = pop();
@@ -605,7 +606,7 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     debugEvent("Method");
     // TODO(danrubel): Consider removing the beginParam parameter
@@ -643,13 +644,33 @@
     // for better error recovery?
     InterfaceType thisType =
         extensionThis == null ? currentDeclaration?.thisType : null;
-    TypeInferrer typeInferrer =
-        typeInferenceEngine?.createLocalTypeInferrer(uri, thisType, library);
+    TypeInferrer typeInferrer = typeInferenceEngine?.createLocalTypeInferrer(
+        uri, thisType, libraryBuilder);
     ConstantContext constantContext = builder.isConstructor && builder.isConst
         ? ConstantContext.inferred
         : ConstantContext.none;
+    return createListenerInternal(
+        builder,
+        memberScope,
+        formalParameterScope,
+        isDeclarationInstanceMember,
+        extensionThis,
+        extensionTypeParameters,
+        typeInferrer,
+        constantContext);
+  }
+
+  StackListener createListenerInternal(
+      ModifierBuilder builder,
+      Scope memberScope,
+      Scope formalParameterScope,
+      bool isDeclarationInstanceMember,
+      VariableDeclaration extensionThis,
+      List<TypeParameter> extensionTypeParameters,
+      TypeInferrer typeInferrer,
+      ConstantContext constantContext) {
     return new BodyBuilder(
-        library: library,
+        libraryBuilder: libraryBuilder,
         member: builder,
         enclosingScope: memberScope,
         formalParameterScope: formalParameterScope,
@@ -738,7 +759,7 @@
   }
 
   @override
-  void beginClassOrMixinBody(ClassKind kind, Token token) {
+  void beginClassOrMixinBody(DeclarationKind kind, Token token) {
     assert(checkState(token, [
       ValueKind.Token,
       ValueKind.NameOrParserRecovery,
@@ -749,7 +770,7 @@
     Object name = pop();
     pop(); // Annotation begin token.
     assert(currentDeclaration == null);
-    assert(memberScope == library.scope);
+    assert(memberScope == libraryBuilder.scope);
     if (name is ParserRecovery) {
       currentClassIsParserRecovery = true;
       return;
@@ -760,11 +781,11 @@
 
   @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     debugEvent("ClassOrMixinBody");
     currentDeclaration = null;
     currentClassIsParserRecovery = false;
-    memberScope = library.scope;
+    memberScope = libraryBuilder.scope;
   }
 
   @override
@@ -796,7 +817,7 @@
     debugEvent("beginExtensionDeclaration");
     String name = nameToken?.lexeme ??
         // Synthesized name used internally.
-        'extension#${unnamedExtensionCounter++}';
+        '_extension#${unnamedExtensionCounter++}';
     push(name);
     push(extensionKeyword);
   }
@@ -889,7 +910,8 @@
     if (isTopLevel) {
       token = parser.parseTopLevelMember(metadata ?? token);
     } else {
-      token = parser.parseClassOrMixinMember(metadata ?? token).next;
+      // TODO(danrubel): disambiguate between class/mixin/extension members
+      token = parser.parseClassMember(metadata ?? token, null).next;
     }
     listenerFinishFields(listener, startToken, metadata, isTopLevel);
     listener.checkEmpty(token.charOffset);
@@ -910,9 +932,9 @@
         declaration = currentDeclaration.scope.local[name];
       }
     } else if (getOrSet != null && optional("set", getOrSet)) {
-      declaration = library.scope.setters[name];
+      declaration = libraryBuilder.scope.setters[name];
     } else {
-      declaration = library.scopeBuilder[name];
+      declaration = libraryBuilder.scopeBuilder[name];
     }
     declaration = handleDuplicatedName(declaration, token);
     checkBuilder(token, declaration, name);
@@ -977,7 +999,7 @@
   @override
   void addProblem(Message message, int charOffset, int length,
       {bool wasHandled: false, List<LocatedMessage> context}) {
-    library.addProblem(message, charOffset, length, uri,
+    libraryBuilder.addProblem(message, charOffset, length, uri,
         wasHandled: wasHandled, context: context);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 65d70e6..13ee5bc 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -25,7 +25,6 @@
         messageExpectedBlockToSkip,
         messageInterpolationInUri,
         messageOperatorWithOptionalFormals,
-        messageStaticConstructor,
         messageTypedefNotFunction,
         Template,
         templateCycleInTypeVariables,
@@ -76,7 +75,7 @@
 import '../parser.dart'
     show
         Assert,
-        ClassKind,
+        DeclarationKind,
         FormalParameterKind,
         IdentifierContext,
         lengthOfSpan,
@@ -454,7 +453,7 @@
   }
 
   @override
-  void beginClassOrNamedMixinApplication(Token token) {
+  void beginClassOrNamedMixinApplicationPrelude(Token token) {
     debugEvent("beginClassOrNamedMixinApplication");
     library.beginNestedDeclaration(
         TypeParameterScopeKind.classOrNamedMixinApplication,
@@ -481,12 +480,16 @@
   }
 
   @override
-  void beginClassOrMixinBody(ClassKind kind, Token token) {
-    if (kind == ClassKind.Extension) {
-      assert(checkState(token, [ValueKind.TypeBuilder]));
-      TypeBuilder extensionThisType = peek();
-      library.currentTypeParameterScopeBuilder
-          .registerExtensionThisType(extensionThisType);
+  void beginClassOrMixinBody(DeclarationKind kind, Token token) {
+    if (kind == DeclarationKind.Extension) {
+      assert(checkState(token, [
+        unionOfKinds([ValueKind.ParserRecovery, ValueKind.TypeBuilder])
+      ]));
+      Object extensionThisType = peek();
+      if (extensionThisType is TypeBuilder) {
+        library.currentTypeParameterScopeBuilder
+            .registerExtensionThisType(extensionThisType);
+      }
     }
     debugEvent("beginClassOrMixinBody");
     // Resolve unresolved types from the class header (i.e., superclass, mixins,
@@ -629,17 +632,23 @@
   }
 
   @override
+  void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+    assert(checkState(extensionKeyword, [ValueKind.MetadataListOrNull]));
+    debugEvent("beginExtensionDeclaration");
+    library.beginNestedDeclaration(
+        TypeParameterScopeKind.extensionDeclaration, "extension");
+  }
+
+  @override
   void beginExtensionDeclaration(Token extensionKeyword, Token nameToken) {
     assert(checkState(extensionKeyword,
         [ValueKind.TypeVariableListOrNull, ValueKind.MetadataListOrNull]));
     debugEvent("beginExtensionDeclaration");
-    library.beginNestedDeclaration(
-        TypeParameterScopeKind.extensionDeclaration, "extension");
     List<TypeVariableBuilder> typeVariables = pop();
     int offset = nameToken?.charOffset ?? extensionKeyword.charOffset;
     String name = nameToken?.lexeme ??
         // Synthesized name used internally.
-        'extension#${unnamedExtensionCounter++}';
+        '_extension#${unnamedExtensionCounter++}';
     push(name);
     push(offset);
     push(typeVariables ?? NullValue.TypeVariables);
@@ -651,7 +660,7 @@
   void endExtensionDeclaration(
       Token extensionKeyword, Token onKeyword, Token endToken) {
     assert(checkState(extensionKeyword, [
-      ValueKind.TypeBuilder,
+      unionOfKinds([ValueKind.ParserRecovery, ValueKind.TypeBuilder]),
       ValueKind.TypeVariableListOrNull,
       ValueKind.Integer,
       ValueKind.NameOrNull,
@@ -805,10 +814,7 @@
       modifiers.add(External);
     }
     if (staticToken != null) {
-      if (inConstructor) {
-        handleRecoverableError(
-            messageStaticConstructor, staticToken, staticToken);
-      } else {
+      if (!inConstructor) {
         modifiers ??= <Modifier>[];
         modifiers.add(Static);
       }
@@ -838,7 +844,7 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     assert(checkState(beginToken, [ValueKind.MethodBody]));
     debugEvent("Method");
@@ -961,17 +967,15 @@
         // We synthesize the names of the generated [TypeParameter]s, i.e.
         // rename 'T' to '#T'. We cannot do it on the builders because their
         // names are used to create the scope.
-        // TODO(johnniwinther): Handle shadowing of extension type variables.
         List<TypeVariableBuilder> synthesizedTypeVariables = library
             .copyTypeVariables(extension.typeVariables, declarationBuilder,
-                // TODO(johnniwinther): The synthesized names show up in
-                // messages. Move synthesizing of names later to avoid this.
-                synthesizeTypeParameterNames: true);
+                isExtensionTypeParameter: true);
         substitution = {};
         for (int i = 0; i < synthesizedTypeVariables.length; i++) {
           substitution[extension.typeVariables[i]] =
               new NamedTypeBuilder.fromTypeDeclarationBuilder(
-                  synthesizedTypeVariables[i]);
+                  synthesizedTypeVariables[i],
+                  const NullabilityBuilder.pendingImplementation());
         }
         if (typeVariables != null) {
           typeVariables = synthesizedTypeVariables..addAll(typeVariables);
@@ -982,8 +986,11 @@
       List<FormalParameterBuilder> synthesizedFormals = [];
       TypeBuilder thisType = extension.extensionThisType;
       if (substitution != null) {
-        thisType = thisType.subst(substitution);
-        declarationBuilder.addType(new UnresolvedType(thisType, -1, null));
+        List<NamedTypeBuilder> unboundTypes = [];
+        thisType = thisType.subst(substitution, unboundTypes);
+        for (NamedTypeBuilder unboundType in unboundTypes) {
+          extension.addType(new UnresolvedType(unboundType, -1, null));
+        }
       }
       synthesizedFormals.add(new FormalParameterBuilder(
           null, finalMask, thisType, "#this", null, charOffset));
@@ -1129,13 +1136,18 @@
     if (!library.loader.target.enableNonNullable) {
       reportErrorIfNullableType(questionMark);
     }
+    bool isMarkedAsNullable = questionMark != null;
     List<TypeBuilder> arguments = pop();
     int charOffset = pop();
     Object name = pop();
     if (name is ParserRecovery) {
       push(name);
     } else {
-      push(library.addNamedType(name, arguments, charOffset));
+      push(library.addNamedType(
+          name,
+          library.computeNullabilityFromToken(isMarkedAsNullable),
+          arguments,
+          charOffset));
     }
   }
 
@@ -1479,7 +1491,7 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     debugEvent("Fields");
     if (!library.loader.target.enableNonNullable) {
@@ -1606,6 +1618,12 @@
                 : templateCycleInTypeVariables.withArguments(
                     builder.name, via.join("', '"));
             addProblem(message, builder.charOffset, builder.name.length);
+            builder.bound = new NamedTypeBuilder(builder.name,
+                const NullabilityBuilder.pendingImplementation(), null)
+              ..bind(new InvalidTypeBuilder(
+                  builder.name,
+                  message.withLocation(
+                      uri, builder.charOffset, builder.name.length)));
           }
         }
       }
@@ -1662,9 +1680,9 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    debugEvent("FactoryMethod");
+    debugEvent("ClassFactoryMethod");
     MethodBody kind = pop();
     ConstructorReferenceBuilder redirectionTarget;
     if (kind == MethodBody.RedirectingFactoryBody) {
@@ -1797,7 +1815,7 @@
 
   @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     debugEvent("ClassOrMixinBody");
   }
 
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 7edee90..a55b41d 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
@@ -33,6 +33,7 @@
         NamedTypeBuilder,
         LibraryBuilder,
         MetadataBuilder,
+        NullabilityBuilder,
         Scope,
         TypeBuilder,
         TypeVariableBuilder,
@@ -129,10 +130,10 @@
             cls.addMember(field);
           }
         } else if (declaration is FunctionBuilder) {
-          Member function = declaration.build(library);
-          function.parent = cls;
+          Member member = declaration.build(library);
+          member.parent = cls;
           if (!declaration.isPatch && declaration.next == null) {
-            cls.addMember(function);
+            cls.addMember(member);
           }
         } else {
           unhandled("${declaration.runtimeType}", "buildBuilders",
@@ -257,7 +258,8 @@
       }
     }
     if (message != null) {
-      return new NamedTypeBuilder(supertype.name, null)
+      return new NamedTypeBuilder(supertype.name,
+          const NullabilityBuilder.pendingImplementation(), null)
         ..bind(new InvalidTypeBuilder(supertype.name,
             message.withLocation(fileUri, charOffset, noLength)));
     }
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 fd87fa7..1961514 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
@@ -15,7 +15,7 @@
 import 'source_library_builder.dart';
 import '../kernel/kernel_builder.dart';
 
-import '../problems.dart' show unexpected, unhandled;
+import '../problems.dart';
 
 import '../fasta_codes.dart'
     show
@@ -48,7 +48,10 @@
         super(metadata, modifiers, name, parent, nameOffset, scope,
             typeParameters, onType);
 
-  Extension build(SourceLibraryBuilder library, LibraryBuilder coreLibrary) {
+  Extension get extension => _extension;
+
+  Extension build(
+      SourceLibraryBuilder libraryBuilder, LibraryBuilder coreLibrary) {
     void buildBuilders(String name, Builder declaration) {
       do {
         if (declaration.parent != this) {
@@ -60,21 +63,50 @@
                 charOffset, fileUri);
           }
         } else if (declaration is FieldBuilder) {
-          Field field = declaration.build(library);
-          library.target.addMember(field);
+          Field field = declaration.build(libraryBuilder);
+          libraryBuilder.library.addMember(field);
           _extension.members.add(new ExtensionMemberDescriptor(
-              name: new Name(declaration.name, library.target),
+              name: new Name(declaration.name, libraryBuilder.library),
               member: field.reference,
-              isStatic: declaration.isStatic));
-        } else if (declaration is FunctionBuilder) {
-          Member function = declaration.build(library);
-          library.target.addMember(function);
+              isStatic: declaration.isStatic,
+              kind: ExtensionMemberKind.Field));
+        } else if (declaration is ProcedureBuilder) {
+          Member function = declaration.build(libraryBuilder);
+          libraryBuilder.library.addMember(function);
+          ExtensionMemberKind kind;
+          switch (declaration.kind) {
+            case ProcedureKind.Method:
+              kind = ExtensionMemberKind.Method;
+              break;
+            case ProcedureKind.Getter:
+              kind = ExtensionMemberKind.Getter;
+              break;
+            case ProcedureKind.Setter:
+              kind = ExtensionMemberKind.Setter;
+              break;
+            case ProcedureKind.Operator:
+              kind = ExtensionMemberKind.Operator;
+              break;
+            case ProcedureKind.Factory:
+              unsupported("Extension method kind: ${declaration.kind}",
+                  declaration.charOffset, declaration.fileUri);
+          }
           _extension.members.add(new ExtensionMemberDescriptor(
-              name: new Name(declaration.name, library.target),
+              name: new Name(declaration.name, libraryBuilder.library),
               member: function.reference,
               isStatic: declaration.isStatic,
               isExternal: declaration.isExternal,
-              kind: declaration.kind));
+              kind: kind));
+          Procedure tearOff = declaration.extensionTearOff;
+          if (tearOff != null) {
+            libraryBuilder.library.addMember(tearOff);
+            _extension.members.add(new ExtensionMemberDescriptor(
+                name: new Name(declaration.name, libraryBuilder.library),
+                member: tearOff.reference,
+                isStatic: false,
+                isExternal: false,
+                kind: ExtensionMemberKind.TearOff));
+          }
         } else {
           unhandled("${declaration.runtimeType}", "buildBuilders",
               declaration.charOffset, declaration.fileUri);
@@ -108,7 +140,7 @@
       }
     });
 
-    _extension.onType = onType?.build(library);
+    _extension.onType = onType?.build(libraryBuilder);
 
     return _extension;
   }
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 5747b08..308acca 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
@@ -72,6 +72,7 @@
         NameIterator,
         PrefixBuilder,
         FunctionBuilder,
+        NullabilityBuilder,
         QualifiedName,
         Scope,
         TypeBuilder,
@@ -278,6 +279,7 @@
   /// an error reading its source.
   Message accessProblem;
 
+  @override
   final Library library;
 
   final SourceLibraryBuilder actualOrigin;
@@ -357,7 +359,9 @@
             scope,
             actualOrigin,
             target ??
-                (actualOrigin?.library ?? new Library(uri, fileUri: fileUri)),
+                (actualOrigin?.library ?? new Library(uri, fileUri: fileUri)
+                  ..setLanguageVersion(loader.target.currentSdkVersionMajor,
+                      loader.target.currentSdkVersionMinor)),
             nameOrigin);
 
   @override
@@ -376,7 +380,7 @@
 
   @override
   void setLanguageVersion(int major, int minor,
-      {int offset: 0, int length: noLength, bool explicit}) {
+      {int offset: 0, int length: noLength, bool explicit: false}) {
     if (languageVersionExplicitlySet) return;
     if (explicit) languageVersionExplicitlySet = true;
 
@@ -386,15 +390,15 @@
       return;
     }
 
-    // If no language version has been set, the default is used.
-    // If trying to set a langauge version that is higher than the "already-set"
+    // If trying to set a langauge version that is higher than the current sdk
     // version it's an error.
-    if (major > library.languageVersionMajor ||
-        (major == library.languageVersionMajor &&
-            minor > library.languageVersionMinor)) {
+    if (major > loader.target.currentSdkVersionMajor ||
+        (major == loader.target.currentSdkVersionMajor &&
+            minor > loader.target.currentSdkVersionMinor)) {
       addPostponedProblem(
           templateLanguageVersionTooHigh.withArguments(
-              library.languageVersionMajor, library.languageVersionMinor),
+              loader.target.currentSdkVersionMajor,
+              loader.target.currentSdkVersionMinor),
           offset,
           length,
           fileUri);
@@ -723,6 +727,9 @@
                     existing.fileUri, existing.charOffset, fullName.length)
           ]);
     }
+    if (declaration.isExtension) {
+      currentTypeParameterScopeBuilder.extensions.add(declaration);
+    }
     return members[name] = declaration;
   }
 
@@ -983,9 +990,9 @@
     boundlessTypeVariables.addAll(part.boundlessTypeVariables);
     // Check that the targets are different. This is not normally a problem
     // but is for patch files.
-    if (target != part.target && part.target.problemsAsJson != null) {
-      target.problemsAsJson ??= <String>[];
-      target.problemsAsJson.addAll(part.target.problemsAsJson);
+    if (library != part.library && part.library.problemsAsJson != null) {
+      library.problemsAsJson ??= <String>[];
+      library.problemsAsJson.addAll(part.library.problemsAsJson);
     }
     List<FieldBuilder> partImplicitlyTypedFields =
         part.takeImplicitlyTypedFields();
@@ -1049,7 +1056,15 @@
               while (memberLast.next != null) {
                 memberLast = memberLast.next;
               }
-              library.additionalExports.add(memberLast.target.reference);
+              if (memberLast is ClassBuilder) {
+                library.additionalExports.add(memberLast.cls.reference);
+              } else if (memberLast is TypeAliasBuilder) {
+                library.additionalExports.add(memberLast.typedef.reference);
+              } else if (memberLast is ExtensionBuilder) {
+                library.additionalExports.add(memberLast.extension.reference);
+              } else {
+                library.additionalExports.add(memberLast.target.reference);
+              }
             }
         }
       }
@@ -1070,6 +1085,9 @@
     } else {
       map[name] = member;
     }
+    if (member.isExtension) {
+      importScope.addExtension(member);
+    }
   }
 
   /// Resolves all unresolved types in [types]. The list of types is cleared
@@ -1138,9 +1156,6 @@
   @override
   SourceLibraryBuilder get origin => actualOrigin ?? this;
 
-  @override
-  Library get target => library;
-
   Uri get uri => library.importUri;
 
   void addSyntheticDeclarationOfDynamic() {
@@ -1148,9 +1163,10 @@
         "dynamic", new DynamicTypeBuilder(const DynamicType(), this, -1), -1);
   }
 
-  TypeBuilder addNamedType(
-      Object name, List<TypeBuilder> arguments, int charOffset) {
-    return addType(new NamedTypeBuilder(name, arguments), charOffset);
+  TypeBuilder addNamedType(Object name, NullabilityBuilder nullabilityBuilder,
+      List<TypeBuilder> arguments, int charOffset) {
+    return addType(
+        new NamedTypeBuilder(name, nullabilityBuilder, arguments), charOffset);
   }
 
   TypeBuilder addMixinApplication(
@@ -1159,7 +1175,9 @@
   }
 
   TypeBuilder addVoidType(int charOffset) {
-    return addNamedType("void", null, charOffset)
+    // 'void' is always nullable.
+    return addNamedType(
+        "void", const NullabilityBuilder.nullable(), null, charOffset)
       ..bind(new VoidTypeBuilder(const VoidType(), this, charOffset));
   }
 
@@ -1204,8 +1222,8 @@
         severity: severity,
         problemOnLibrary: true);
     if (formattedMessage != null) {
-      target.problemsAsJson ??= <String>[];
-      target.problemsAsJson.add(formattedMessage.toJsonString());
+      library.problemsAsJson ??= <String>[];
+      library.problemsAsJson.add(formattedMessage.toJsonString());
     }
     return formattedMessage;
   }
@@ -1286,14 +1304,17 @@
     Map<String, MemberBuilder> constructors = declaration.constructors;
     Map<String, MemberBuilder> setters = declaration.setters;
 
-    Scope classScope = new Scope(members, setters,
-        scope.withTypeVariables(typeVariables), "class $className",
+    Scope classScope = new Scope(
+        local: members,
+        setters: setters,
+        parent: scope.withTypeVariables(typeVariables),
+        debugName: "class $className",
         isModifiable: false);
 
     // When looking up a constructor, we don't consider type variables or the
     // library scope.
-    Scope constructorScope =
-        new Scope(constructors, null, null, className, isModifiable: false);
+    Scope constructorScope = new Scope(
+        local: constructors, debugName: className, isModifiable: false);
     bool isMixinDeclaration = false;
     if (modifiers & mixinDeclarationMask != 0) {
       isMixinDeclaration = true;
@@ -1302,7 +1323,7 @@
     if (declaration.hasConstConstructor) {
       modifiers |= hasConstConstructorMask;
     }
-    ClassBuilder cls = new SourceClassBuilder(
+    ClassBuilder classBuilder = new SourceClassBuilder(
         metadata,
         modifiers,
         className,
@@ -1323,14 +1344,14 @@
         endOffset,
         isMixinDeclaration: isMixinDeclaration);
     loader.target.metadataCollector
-        ?.setDocumentationComment(cls.target, documentationComment);
+        ?.setDocumentationComment(classBuilder.cls, documentationComment);
 
     constructorReferences.clear();
     Map<String, TypeVariableBuilder> typeVariablesByName =
-        checkTypeVariables(typeVariables, cls);
+        checkTypeVariables(typeVariables, classBuilder);
     void setParent(String name, MemberBuilder member) {
       while (member != null) {
-        member.parent = cls;
+        member.parent = classBuilder;
         member = member.next;
       }
     }
@@ -1339,8 +1360,10 @@
       if (typeVariablesByName != null) {
         TypeVariableBuilder tv = typeVariablesByName[name];
         if (tv != null) {
-          cls.addProblem(templateConflictsWithTypeVariable.withArguments(name),
-              member.charOffset, name.length,
+          classBuilder.addProblem(
+              templateConflictsWithTypeVariable.withArguments(name),
+              member.charOffset,
+              name.length,
               context: [
                 messageConflictsWithTypeVariableCause.withLocation(
                     tv.fileUri, tv.charOffset, name.length)
@@ -1353,7 +1376,7 @@
     members.forEach(setParentAndCheckConflicts);
     constructors.forEach(setParentAndCheckConflicts);
     setters.forEach(setParentAndCheckConflicts);
-    addBuilder(className, cls, nameOffset);
+    addBuilder(className, classBuilder, nameOffset);
   }
 
   Map<String, TypeVariableBuilder> checkTypeVariables(
@@ -1364,14 +1387,21 @@
     for (TypeVariableBuilder tv in typeVariables) {
       TypeVariableBuilder existing = typeVariablesByName[tv.name];
       if (existing != null) {
-        addProblem(messageTypeVariableDuplicatedName, tv.charOffset,
-            tv.name.length, fileUri,
-            context: [
-              templateTypeVariableDuplicatedNameCause
-                  .withArguments(tv.name)
-                  .withLocation(
-                      fileUri, existing.charOffset, existing.name.length)
-            ]);
+        if (existing.isExtensionTypeParameter) {
+          // The type parameter from the extension is shadowed by the type
+          // parameter from the member. Rename the shadowed type parameter.
+          existing.parameter.name = '#${existing.name}';
+          typeVariablesByName[tv.name] = tv;
+        } else {
+          addProblem(messageTypeVariableDuplicatedName, tv.charOffset,
+              tv.name.length, fileUri,
+              context: [
+                templateTypeVariableDuplicatedNameCause
+                    .withArguments(tv.name)
+                    .withLocation(
+                        fileUri, existing.charOffset, existing.name.length)
+              ]);
+        }
       } else {
         typeVariablesByName[tv.name] = tv;
         if (owner is ClassBuilder) {
@@ -1406,11 +1436,14 @@
     Map<String, MemberBuilder> constructors = declaration.constructors;
     Map<String, MemberBuilder> setters = declaration.setters;
 
-    Scope classScope = new Scope(members, setters,
-        scope.withTypeVariables(typeVariables), "extension $extensionName",
+    Scope classScope = new Scope(
+        local: members,
+        setters: setters,
+        parent: scope.withTypeVariables(typeVariables),
+        debugName: "extension $extensionName",
         isModifiable: false);
 
-    ExtensionBuilder extension = new SourceExtensionBuilder(
+    ExtensionBuilder extensionBuilder = new SourceExtensionBuilder(
         metadata,
         modifiers,
         extensionName,
@@ -1421,15 +1454,15 @@
         startOffset,
         nameOffset,
         endOffset);
-    loader.target.metadataCollector
-        ?.setDocumentationComment(extension.target, documentationComment);
+    loader.target.metadataCollector?.setDocumentationComment(
+        extensionBuilder.extension, documentationComment);
 
     constructorReferences.clear();
     Map<String, TypeVariableBuilder> typeVariablesByName =
-        checkTypeVariables(typeVariables, extension);
+        checkTypeVariables(typeVariables, extensionBuilder);
     void setParent(String name, MemberBuilder member) {
       while (member != null) {
-        member.parent = extension;
+        member.parent = extensionBuilder;
         member = member.next;
       }
     }
@@ -1438,7 +1471,7 @@
       if (typeVariablesByName != null) {
         TypeVariableBuilder tv = typeVariablesByName[name];
         if (tv != null) {
-          extension.addProblem(
+          extensionBuilder.addProblem(
               templateConflictsWithTypeVariable.withArguments(name),
               member.charOffset,
               name.length,
@@ -1454,7 +1487,7 @@
     members.forEach(setParentAndCheckConflicts);
     constructors.forEach(setParentAndCheckConflicts);
     setters.forEach(setParentAndCheckConflicts);
-    addBuilder(extensionName, extension, nameOffset);
+    addBuilder(extensionName, extensionBuilder, nameOffset);
   }
 
   TypeBuilder applyMixins(TypeBuilder type, int startCharOffset, int charOffset,
@@ -1624,13 +1657,17 @@
 
             applicationTypeArguments = <TypeBuilder>[];
             for (TypeVariableBuilder typeVariable in typeVariables) {
-              applicationTypeArguments
-                  .add(addNamedType(typeVariable.name, null, charOffset)..bind(
-                      // The type variable types passed as arguments to the
-                      // generic class representing the anonymous mixin
-                      // application should refer back to the type variables of
-                      // the class that extend the anonymous mixin application.
-                      typeVariable));
+              applicationTypeArguments.add(addNamedType(
+                  typeVariable.name,
+                  const NullabilityBuilder.pendingImplementation(),
+                  null,
+                  charOffset)
+                ..bind(
+                    // The type variable types passed as arguments to the
+                    // generic class representing the anonymous mixin
+                    // application should refer back to the type variables of
+                    // the class that extend the anonymous mixin application.
+                    typeVariable));
             }
           }
         }
@@ -1650,10 +1687,15 @@
                 ? interfaces
                 : isMixinDeclaration ? [supertype, mixin] : null,
             null, // No `on` clause types.
-            new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
-                scope.withTypeVariables(typeVariables),
-                "mixin $fullname ", isModifiable: false),
-            new Scope(<String, MemberBuilder>{}, null, null, fullname,
+            new Scope(
+                local: <String, MemberBuilder>{},
+                setters: <String, MemberBuilder>{},
+                parent: scope.withTypeVariables(typeVariables),
+                debugName: "mixin $fullname ",
+                isModifiable: false),
+            new Scope(
+                local: <String, MemberBuilder>{},
+                debugName: fullname,
                 isModifiable: false),
             this,
             <ConstructorReferenceBuilder>[],
@@ -1662,16 +1704,19 @@
             charEndOffset,
             mixedInType: isMixinDeclaration ? null : mixin);
         if (isNamedMixinApplication) {
-          loader.target.metadataCollector?.setDocumentationComment(
-              application.target, documentationComment);
+          loader.target.metadataCollector
+              ?.setDocumentationComment(application.cls, documentationComment);
         }
         // TODO(ahe, kmillikin): Should always be true?
         // pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
         // handle that :(
         application.cls.isAnonymousMixin = !isNamedMixinApplication;
         addBuilder(fullname, application, charOffset);
-        supertype =
-            addNamedType(fullname, applicationTypeArguments, charOffset);
+        supertype = addNamedType(
+            fullname,
+            const NullabilityBuilder.pendingImplementation(),
+            applicationTypeArguments,
+            charOffset);
       }
       return supertype;
     } else {
@@ -1718,16 +1763,17 @@
     if (hasInitializer) {
       modifiers |= hasInitializerMask;
     }
-    FieldBuilder field = new FieldBuilder(
+    FieldBuilder fieldBuilder = new FieldBuilder(
         metadata, type, name, modifiers, this, charOffset, charEndOffset);
-    field.constInitializerToken = constInitializerToken;
-    addBuilder(name, field, charOffset);
+    fieldBuilder.constInitializerToken = constInitializerToken;
+    addBuilder(name, fieldBuilder, charOffset);
     if (!legacyMode && type == null && initializerToken != null) {
-      field.target.type = new ImplicitFieldType(field, initializerToken);
-      (implicitlyTypedFields ??= <FieldBuilder>[]).add(field);
+      fieldBuilder.field.type =
+          new ImplicitFieldType(fieldBuilder, initializerToken);
+      (implicitlyTypedFields ??= <FieldBuilder>[]).add(fieldBuilder);
     }
     loader.target.metadataCollector
-        ?.setDocumentationComment(field.target, documentationComment);
+        ?.setDocumentationComment(fieldBuilder.field, documentationComment);
   }
 
   void addConstructor(
@@ -1746,7 +1792,7 @@
       String nativeMethodName,
       {Token beginInitializers}) {
     MetadataCollector metadataCollector = loader.target.metadataCollector;
-    ConstructorBuilder procedure = new ConstructorBuilder(
+    ConstructorBuilder constructorBuilder = new ConstructorBuilder(
         metadata,
         modifiers & ~abstractMask,
         returnType,
@@ -1760,18 +1806,20 @@
         charEndOffset,
         nativeMethodName);
     metadataCollector?.setDocumentationComment(
-        procedure.target, documentationComment);
-    metadataCollector?.setConstructorNameOffset(procedure.target, name);
-    checkTypeVariables(typeVariables, procedure);
-    addBuilder(constructorName, procedure, charOffset);
+        constructorBuilder.constructor, documentationComment);
+    metadataCollector?.setConstructorNameOffset(
+        constructorBuilder.constructor, name);
+    checkTypeVariables(typeVariables, constructorBuilder);
+    addBuilder(constructorName, constructorBuilder, charOffset);
     if (nativeMethodName != null) {
-      addNativeMethod(procedure);
+      addNativeMethod(constructorBuilder);
     }
-    if (procedure.isConst) {
+    if (constructorBuilder.isConst) {
       currentTypeParameterScopeBuilder?.hasConstConstructor = true;
       // const constructors will have their initializers compiled and written
       // into the outline.
-      procedure.beginInitializers = beginInitializers ?? Token.eof(-1);
+      constructorBuilder.beginInitializers =
+          beginInitializers ?? new Token.eof(-1);
     }
   }
 
@@ -1799,7 +1847,7 @@
         returnType = addVoidType(charOffset);
       }
     }
-    FunctionBuilder procedure = new ProcedureBuilder(
+    ProcedureBuilder procedureBuilder = new ProcedureBuilder(
         metadata,
         modifiers,
         returnType,
@@ -1814,11 +1862,11 @@
         charEndOffset,
         nativeMethodName);
     metadataCollector?.setDocumentationComment(
-        procedure.target, documentationComment);
-    checkTypeVariables(typeVariables, procedure);
-    addBuilder(name, procedure, charOffset);
+        procedureBuilder.procedure, documentationComment);
+    checkTypeVariables(typeVariables, procedureBuilder);
+    addBuilder(name, procedureBuilder, charOffset);
     if (nativeMethodName != null) {
-      addNativeMethod(procedure);
+      addNativeMethod(procedureBuilder);
     }
   }
 
@@ -1836,6 +1884,7 @@
       String nativeMethodName) {
     TypeBuilder returnType = addNamedType(
         currentTypeParameterScopeBuilder.parent.name,
+        const NullabilityBuilder.omitted(),
         <TypeBuilder>[],
         charOffset);
     // Nested declaration began in `OutlineBuilder.beginFactoryMethod`.
@@ -1852,9 +1901,9 @@
       procedureName = name;
     }
 
-    ProcedureBuilder procedure;
+    ProcedureBuilder procedureBuilder;
     if (redirectionTarget != null) {
-      procedure = new RedirectingFactoryBuilder(
+      procedureBuilder = new RedirectingFactoryBuilder(
           metadata,
           staticMask | modifiers,
           returnType,
@@ -1872,7 +1921,7 @@
           nativeMethodName,
           redirectionTarget);
     } else {
-      procedure = new ProcedureBuilder(
+      procedureBuilder = new ProcedureBuilder(
           metadata,
           staticMask | modifiers,
           returnType,
@@ -1893,22 +1942,24 @@
 
     MetadataCollector metadataCollector = loader.target.metadataCollector;
     metadataCollector?.setDocumentationComment(
-        procedure.target, documentationComment);
-    metadataCollector?.setConstructorNameOffset(procedure.target, name);
+        procedureBuilder.procedure, documentationComment);
+    metadataCollector?.setConstructorNameOffset(
+        procedureBuilder.procedure, name);
 
     TypeParameterScopeBuilder savedDeclaration =
         currentTypeParameterScopeBuilder;
     currentTypeParameterScopeBuilder = factoryDeclaration;
-    for (TypeVariableBuilder tv in procedure.typeVariables) {
-      NamedTypeBuilder t = procedure.returnType;
-      t.arguments.add(addNamedType(tv.name, null, procedure.charOffset));
+    for (TypeVariableBuilder tv in procedureBuilder.typeVariables) {
+      NamedTypeBuilder t = procedureBuilder.returnType;
+      t.arguments.add(addNamedType(tv.name, const NullabilityBuilder.omitted(),
+          null, procedureBuilder.charOffset));
     }
     currentTypeParameterScopeBuilder = savedDeclaration;
 
-    factoryDeclaration.resolveTypes(procedure.typeVariables, this);
-    addBuilder(procedureName, procedure, charOffset);
+    factoryDeclaration.resolveTypes(procedureBuilder.typeVariables, this);
+    addBuilder(procedureName, procedureBuilder, charOffset);
     if (nativeMethodName != null) {
-      addNativeMethod(procedure);
+      addNativeMethod(procedureBuilder);
     }
   }
 
@@ -1925,7 +1976,7 @@
         enumConstantInfos, this, startCharOffset, charOffset, charEndOffset);
     addBuilder(name, builder, charOffset);
     metadataCollector?.setDocumentationComment(
-        builder.target, documentationComment);
+        builder.cls, documentationComment);
   }
 
   void addFunctionTypeAlias(
@@ -1935,15 +1986,15 @@
       List<TypeVariableBuilder> typeVariables,
       FunctionTypeBuilder type,
       int charOffset) {
-    TypeAliasBuilder typedef = new TypeAliasBuilder(
+    TypeAliasBuilder typedefBuilder = new TypeAliasBuilder(
         metadata, name, typeVariables, type, this, charOffset);
     loader.target.metadataCollector
-        ?.setDocumentationComment(typedef.target, documentationComment);
-    checkTypeVariables(typeVariables, typedef);
+        ?.setDocumentationComment(typedefBuilder.typedef, documentationComment);
+    checkTypeVariables(typeVariables, typedefBuilder);
     // Nested declaration began in `OutlineBuilder.beginFunctionTypeAlias`.
     endNestedDeclaration(TypeParameterScopeKind.typedef, "#typedef")
         .resolveTypes(typeVariables, this);
-    addBuilder(name, typedef, charOffset);
+    addBuilder(name, typedefBuilder, charOffset);
   }
 
   FunctionTypeBuilder addFunctionType(
@@ -2098,7 +2149,7 @@
           library.addDependency(import.prefixBuilder.dependency);
         } else {
           library.addDependency(new LibraryDependency.import(
-              import.imported.target,
+              import.imported.library,
               name: import.prefix,
               combinators: toKernelCombinators(import.combinators))
             ..fileOffset = import.charOffset);
@@ -2107,7 +2158,7 @@
         // Add export
         Export export = exports[exportIndex++];
         library.addDependency(new LibraryDependency.export(
-            export.exported.target,
+            export.exported.library,
             combinators: toKernelCombinators(export.combinators))
           ..fileOffset = export.charOffset);
       }
@@ -2302,14 +2353,14 @@
   /// [TypeParameter] are prefix with '#' to indicate that their synthesized.
   List<TypeVariableBuilder> copyTypeVariables(
       List<TypeVariableBuilder> original, TypeParameterScopeBuilder declaration,
-      {bool synthesizeTypeParameterNames: false}) {
+      {bool isExtensionTypeParameter: false}) {
     List<TypeBuilder> newTypes = <TypeBuilder>[];
     List<TypeVariableBuilder> copy = <TypeVariableBuilder>[];
     for (TypeVariableBuilder variable in original) {
       TypeVariableBuilder newVariable = new TypeVariableBuilder(
           variable.name, this, variable.charOffset,
           bound: variable.bound?.clone(newTypes),
-          synthesizeTypeParameterName: synthesizeTypeParameterNames);
+          isExtensionTypeParameter: isExtensionTypeParameter);
       copy.add(newVariable);
       boundlessTypeVariables.add(newVariable);
     }
@@ -2830,10 +2881,10 @@
     while (iterator.moveNext()) {
       Builder declaration = iterator.current;
       if (declaration is FieldBuilder) {
-        checkBoundsInField(declaration.target, typeEnvironment);
+        checkBoundsInField(declaration.field, typeEnvironment);
       } else if (declaration is ProcedureBuilder) {
-        checkBoundsInFunctionNode(
-            declaration.target.function, typeEnvironment, declaration.fileUri);
+        checkBoundsInFunctionNode(declaration.procedure.function,
+            typeEnvironment, declaration.fileUri);
       } else if (declaration is ClassBuilder) {
         declaration.checkBoundsInOutline(typeEnvironment);
       }
@@ -2892,6 +2943,8 @@
 
   final Map<String, Builder> setters;
 
+  final List<ExtensionBuilder> extensions;
+
   final List<UnresolvedType> types = <UnresolvedType>[];
 
   // TODO(johnniwinther): Stop using [_name] for determining the declaration
@@ -2912,14 +2965,28 @@
 
   bool hasConstConstructor = false;
 
-  TypeParameterScopeBuilder(this._kind, this.members, this.setters,
-      this.constructors, this._name, this._charOffset, this.parent) {
+  TypeParameterScopeBuilder(
+      this._kind,
+      this.members,
+      this.setters,
+      this.constructors,
+      this.extensions,
+      this._name,
+      this._charOffset,
+      this.parent) {
     assert(_name != null);
   }
 
   TypeParameterScopeBuilder.library()
-      : this(TypeParameterScopeKind.library, <String, Builder>{},
-            <String, Builder>{}, null, "<library>", -1, null);
+      : this(
+            TypeParameterScopeKind.library,
+            <String, Builder>{},
+            <String, Builder>{},
+            null, // No support for constructors in library scopes.
+            <ExtensionBuilder>[],
+            "<library>",
+            -1,
+            null);
 
   TypeParameterScopeBuilder createNested(
       TypeParameterScopeKind kind, String name, bool hasMembers) {
@@ -2928,6 +2995,7 @@
         hasMembers ? <String, MemberBuilder>{} : null,
         hasMembers ? <String, MemberBuilder>{} : null,
         hasMembers ? <String, MemberBuilder>{} : null,
+        null, // No support for extensions in nested scopes.
         name,
         -1,
         this);
@@ -3092,7 +3160,13 @@
   }
 
   Scope toScope(Scope parent) {
-    return new Scope(members, setters, parent, name, isModifiable: false);
+    return new Scope(
+        local: members,
+        setters: setters,
+        extensions: extensions,
+        parent: parent,
+        debugName: name,
+        isModifiable: false);
   }
 
   @override
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 c954495..f9a2a91 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -113,6 +113,8 @@
         Token,
         scan;
 
+import '../type_inference/type_inferrer.dart';
+
 import 'diet_listener.dart' show DietListener;
 
 import 'diet_parser.dart' show DietParser;
@@ -212,9 +214,6 @@
             enableExtensionMethods: target.enableExtensionMethods,
             enableNonNullable: target.enableNonNullable),
         languageVersionChanged: (_, LanguageVersionToken version) {
-      // TODO(jensj): What if we have several? What if it is unsupported?
-      // What if the language version was already set via packages and this is
-      // higher? Etc
       library.setLanguageVersion(version.major, version.minor,
           offset: version.offset, length: version.length, explicit: true);
     });
@@ -264,6 +263,9 @@
       case "dart:_internal":
         return utf8.encode(defaultDartInternalSource);
 
+      case "dart:typed_data":
+        return utf8.encode(defaultDartTypedDataSource);
+
       default:
         return utf8.encode(message == null ? "" : "/* ${message.message} */");
     }
@@ -809,13 +811,13 @@
   Component computeFullComponent() {
     Set<Library> libraries = new Set<Library>();
     List<Library> workList = <Library>[];
-    builders.forEach((Uri uri, LibraryBuilder library) {
-      if (!library.isPatch &&
-          (library.loader == this ||
-              library.uri.scheme == "dart" ||
-              library == this.first)) {
-        if (libraries.add(library.target)) {
-          workList.add(library.target);
+    builders.forEach((Uri uri, LibraryBuilder libraryBuilder) {
+      if (!libraryBuilder.isPatch &&
+          (libraryBuilder.loader == this ||
+              libraryBuilder.uri.scheme == "dart" ||
+              libraryBuilder == this.first)) {
+        if (libraries.add(libraryBuilder.library)) {
+          workList.add(libraryBuilder.library);
         }
       }
     });
@@ -951,7 +953,7 @@
     for (SourceClassBuilder builder in sourceClasses) {
       if (builder.library.loader == this && !builder.isPatch) {
         if (builder.addNoSuchMethodForwarders(target, hierarchy)) {
-          changedClasses.add(builder.target);
+          changedClasses.add(builder.cls);
         }
       }
     }
@@ -962,10 +964,6 @@
   void checkMixins(List<SourceClassBuilder> sourceClasses) {
     for (SourceClassBuilder builder in sourceClasses) {
       if (builder.library.loader == this && !builder.isPatch) {
-        if (builder.isMixinDeclaration) {
-          builder.checkMixinDeclaration();
-        }
-
         Class mixedInClass = builder.cls.mixedInClass;
         if (mixedInClass != null && mixedInClass.isMixinDeclaration) {
           builder.checkMixinApplication(hierarchy);
@@ -1046,8 +1044,7 @@
       node.accept(collectionTransformer ??= new CollectionTransformer(this));
     }
     if (transformSetLiterals) {
-      node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this,
-          transformConst: !target.enableConstantUpdate2018));
+      node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this));
     }
   }
 
@@ -1061,9 +1058,8 @@
       }
     }
     if (transformSetLiterals) {
-      SetLiteralTransformer transformer = setLiteralTransformer ??=
-          new SetLiteralTransformer(this,
-              transformConst: !target.enableConstantUpdate2018);
+      SetLiteralTransformer transformer =
+          setLiteralTransformer ??= new SetLiteralTransformer(this);
       for (int i = 0; i < list.length; ++i) {
         list[i] = list[i].accept(transformer);
       }
@@ -1121,6 +1117,11 @@
   TypeBuilder computeTypeBuilder(DartType type) {
     return type.accept(new TypeBuilderComputer(this));
   }
+
+  BodyBuilder createBodyBuilderForField(
+      FieldBuilder field, TypeInferrer typeInferrer) {
+    return new BodyBuilder.forField(field, typeInferrer);
+  }
 }
 
 /// A minimal implementation of dart:core that is sufficient to create an
@@ -1264,6 +1265,16 @@
 }
 """;
 
+/// A minimal implementation of dart:typed_data that is sufficient to create an
+/// instance of [CoreTypes] and compile program.
+const String defaultDartTypedDataSource = """
+class Endian {
+  static const Endian little = null;
+  static const Endian big = null;
+  static final Endian host = null;
+}
+""";
+
 class AmbiguousTypesRecord {
   final Class cls;
   final Supertype a;
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 c4de27c..ebf430a 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
@@ -11,7 +11,7 @@
 import '../parser.dart'
     show
         Assert,
-        ClassKind,
+        DeclarationKind,
         FormalParameterKind,
         IdentifierContext,
         Listener,
@@ -314,7 +314,7 @@
 
   @override
   void endClassOrMixinBody(
-      ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+      DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
     debugEvent("ClassOrMixinBody", beginToken);
     state.checkEmpty(endToken);
   }
@@ -545,9 +545,9 @@
   }
 
   @override
-  void endFactoryMethod(
+  void endClassFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
-    debugEvent("FactoryMethod", beginToken);
+    debugEvent("ClassFactoryMethod", beginToken);
     state.pop(); // Name.
     state.checkEmpty(endToken);
   }
@@ -564,7 +564,7 @@
   }
 
   @override
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     debugEvent("Fields", staticToken);
     state.discard(count); // Field names.
@@ -982,7 +982,7 @@
   }
 
   @override
-  void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     debugEvent("endMethod", endToken);
     state.pop(); // Method name.
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 9186a6d..08ecbf0 100644
--- a/pkg/front_end/lib/src/fasta/source/value_kinds.dart
+++ b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
@@ -33,9 +33,9 @@
   /// Checks the [value] an returns `true` if the value is of the expected kind.
   bool check(Object value);
 
-  static const ValueKind Arguments = _SingleValueKind<type.Arguments>();
+  static const ValueKind Arguments = const _SingleValueKind<type.Arguments>();
   static const ValueKind ArgumentsOrNull =
-      _SingleValueKind<type.Arguments>(NullValue.Arguments);
+      const _SingleValueKind<type.Arguments>(NullValue.Arguments);
   static const ValueKind Expression = const _SingleValueKind<type.Expression>();
   static const ValueKind Identifier = const _SingleValueKind<type.Identifier>();
   static const ValueKind IdentifierOrNull =
@@ -55,7 +55,8 @@
   static const ValueKind Name = const _SingleValueKind<String>();
   static const ValueKind NameOrNull =
       const _SingleValueKind<String>(NullValue.Name);
-  static const ValueKind NameOrOperator = _UnionValueKind([Name, Operator]);
+  static const ValueKind NameOrOperator =
+      const _UnionValueKind([Name, Operator]);
   static const ValueKind NameOrQualifiedNameOrOperator =
       const _UnionValueKind([Name, QualifiedName, Operator]);
   static const ValueKind NameOrParserRecovery =
@@ -64,9 +65,9 @@
       const _SingleValueKind<List<type.MetadataBuilder>>(NullValue.Metadata);
   static const ValueKind Operator = const _SingleValueKind<type.Operator>();
   static const ValueKind ParserRecovery =
-      _SingleValueKind<type.ParserRecovery>();
+      const _SingleValueKind<type.ParserRecovery>();
   static const ValueKind ProblemBuilder =
-      _SingleValueKind<type.ProblemBuilder>();
+      const _SingleValueKind<type.ProblemBuilder>();
   static const ValueKind QualifiedName =
       const _SingleValueKind<type.QualifiedName>();
   static const ValueKind Token = const _SingleValueKind<type.Token>();
@@ -143,5 +144,5 @@
 
 /// Helper method for creating a union of a list of [ValueKind]s.
 ValueKind unionOfKinds(List<ValueKind> kinds) {
-  return _UnionValueKind(kinds);
+  return new _UnionValueKind(kinds);
 }
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index dd80c6f..e6ada23 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -48,24 +48,15 @@
   Builder cachedNativeAnnotation;
   Builder cachedNativeExtensionAnnotation;
 
-  bool enableConstantUpdate2018;
-  bool enableControlFlowCollections;
   bool enableExtensionMethods;
   bool enableNonNullable;
-  bool enableSpreadCollections;
   bool enableTripleShift;
 
   TargetImplementation(Ticker ticker, this.uriTranslator, this.backendTarget)
-      : enableConstantUpdate2018 = CompilerContext.current.options
-            .isExperimentEnabled(ExperimentalFlag.constantUpdate2018),
-        enableControlFlowCollections = CompilerContext.current.options
-            .isExperimentEnabled(ExperimentalFlag.controlFlowCollections),
-        enableExtensionMethods = CompilerContext.current.options
+      : enableExtensionMethods = CompilerContext.current.options
             .isExperimentEnabled(ExperimentalFlag.extensionMethods),
         enableNonNullable = CompilerContext.current.options
             .isExperimentEnabled(ExperimentalFlag.nonNullable),
-        enableSpreadCollections = CompilerContext.current.options
-            .isExperimentEnabled(ExperimentalFlag.spreadCollections),
         enableTripleShift = CompilerContext.current.options
             .isExperimentEnabled(ExperimentalFlag.tripleShift),
         super(ticker);
@@ -134,6 +125,11 @@
     for (String uri in backendTarget.extraRequiredLibraries) {
       loader.read(Uri.parse(uri), 0, accessor: loader.coreLibrary);
     }
+    if (context.compilingPlatform) {
+      for (String uri in backendTarget.extraRequiredLibrariesPlatform) {
+        loader.read(Uri.parse(uri), 0, accessor: loader.coreLibrary);
+      }
+    }
   }
 
   void addSourceInformation(
@@ -162,4 +158,37 @@
     }
     return rewriteSeverity(severity, message.code, fileUri);
   }
+
+  String get currentSdkVersion {
+    return CompilerContext.current.options.currentSdkVersion;
+  }
+
+  int _currentSdkVersionMajor;
+  int _currentSdkVersionMinor;
+  int get currentSdkVersionMajor {
+    if (_currentSdkVersionMajor != null) return _currentSdkVersionMajor;
+    _parseCurrentSdkVersion();
+    return _currentSdkVersionMajor;
+  }
+
+  int get currentSdkVersionMinor {
+    if (_currentSdkVersionMinor != null) return _currentSdkVersionMinor;
+    _parseCurrentSdkVersion();
+    return _currentSdkVersionMinor;
+  }
+
+  void _parseCurrentSdkVersion() {
+    bool good = false;
+    if (currentSdkVersion != null) {
+      List<String> dotSeparatedParts = currentSdkVersion.split(".");
+      if (dotSeparatedParts.length >= 2) {
+        _currentSdkVersionMajor = int.tryParse(dotSeparatedParts[0]);
+        _currentSdkVersionMinor = int.tryParse(dotSeparatedParts[1]);
+        good = true;
+      }
+    }
+    if (!good) {
+      throw new StateError("Unparsable sdk version given: $currentSdkVersion");
+    }
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index c690103..d08f492 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -2,17 +2,23 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:kernel/ast.dart' show Arguments, Expression, FunctionType;
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
 import '../fasta_codes.dart' show LocatedMessage, Message;
 
+import '../kernel/forest.dart';
+
 abstract class InferenceHelper {
   CoreTypes get coreTypes;
 
   Uri get uri;
 
+  Forest get forest;
+
   set transformSetLiterals(bool value);
 
   Expression buildProblem(Message message, int charOffset, int length,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 7c8edce..f01431a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
+import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
 import 'package:kernel/ast.dart' as kernel;
 
 import 'package:kernel/ast.dart'
@@ -16,6 +17,7 @@
         DartType,
         DynamicType,
         Expression,
+        Extension,
         Field,
         FunctionExpression,
         FunctionNode,
@@ -39,6 +41,7 @@
         SetLiteral,
         Statement,
         StaticGet,
+        StaticInvocation,
         SuperMethodInvocation,
         SuperPropertyGet,
         SuperPropertySet,
@@ -49,7 +52,8 @@
         TypeParameterType,
         VariableDeclaration,
         VariableGet,
-        VoidType;
+        VoidType,
+        setParents;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
@@ -67,6 +71,9 @@
         InstrumentationValueForType,
         InstrumentationValueForTypeArgs;
 
+import '../builder/extension_builder.dart';
+import '../builder/member_builder.dart';
+
 import '../fasta_codes.dart'
     show
         LocatedMessage,
@@ -105,7 +112,7 @@
         ShadowTypeInferrer,
         VariableDeclarationJudgment,
         getExplicitTypeArguments,
-        getInferredType;
+        getExtensionTypeParameterCount;
 
 import '../kernel/type_algorithms.dart' show hasAnyTypeVariables;
 
@@ -542,7 +549,7 @@
 
   TypeInferrerImpl.private(
       this.engine, this.uri, bool topLevel, this.thisType, this.library)
-      : assert((topLevel && library == null) || (!topLevel && library != null)),
+      : assert(library != null),
         classHierarchy = engine.classHierarchy,
         instrumentation = topLevel ? null : engine.instrumentation,
         typeSchemaEnvironment = engine.typeSchemaEnvironment,
@@ -650,7 +657,7 @@
           PropertyGet tearOff =
               new PropertyGet(new VariableGet(t), callName, callMember)
                 ..fileOffset = fileOffset;
-          actualType = getCalleeType(callMember, actualType);
+          actualType = getGetterTypeForMemberTarget(callMember, actualType);
           ConditionalExpression conditional = new ConditionalExpression(
               nullCheck,
               new NullLiteral()..fileOffset = fileOffset,
@@ -727,6 +734,17 @@
     return type is InterfaceType && type.classNode == coreTypes.nullClass;
   }
 
+  List<DartType> _inferExtensionTypeArguments(
+      List<TypeParameter> typeParameters,
+      DartType onType,
+      DartType receiverType) {
+    List<DartType> inferredTypes =
+        new List<DartType>.filled(typeParameters.length, const UnknownType());
+    typeSchemaEnvironment.inferGenericFunctionOrType(
+        null, typeParameters, [onType], [receiverType], null, inferredTypes);
+    return inferredTypes;
+  }
+
   /// Finds a member of [receiverType] called [name], and if it is found,
   /// reports it through instrumentation using [fileOffset].
   ///
@@ -738,18 +756,20 @@
   /// up targeting it if the arguments do not match (the basic principle is that
   /// the Object member is used for inferring types only if noSuchMethod cannot
   /// be targeted due to, e.g., an incorrect argument count).
-  Object findInterfaceMember(DartType receiverType, Name name, int fileOffset,
+  ObjectAccessTarget findInterfaceMember(
+      DartType receiverType, Name name, int fileOffset,
       {Template<Message Function(String, DartType)> errorTemplate,
       Expression expression,
       Expression receiver,
       bool setter: false,
-      bool instrumented: true}) {
+      bool instrumented: true,
+      bool includeExtensionMethods: false}) {
     assert(receiverType != null && isKnown(receiverType));
 
     receiverType = resolveTypeParameter(receiverType);
 
     if (receiverType is FunctionType && name.name == 'call') {
-      return 'call';
+      return const ObjectAccessTarget.callFunction();
     }
 
     Class classNode = receiverType is InterfaceType
@@ -757,15 +777,113 @@
         : coreTypes.objectClass;
     Member interfaceMember =
         _getInterfaceMember(classNode, name, setter, fileOffset);
+    ObjectAccessTarget target = interfaceMember != null
+        ? new ObjectAccessTarget.interfaceMember(interfaceMember)
+        : const ObjectAccessTarget.unresolved();
     if (instrumented &&
         receiverType != const DynamicType() &&
-        interfaceMember != null) {
+        target.isInstanceMember) {
       instrumentation?.record(uri, fileOffset, 'target',
-          new InstrumentationValueForMember(interfaceMember));
+          new InstrumentationValueForMember(target.member));
+    }
+
+    if (target.isUnresolved && includeExtensionMethods) {
+      ExtensionAccessCandidate bestSoFar;
+      List<ExtensionAccessCandidate> noneMoreSpecific = [];
+      library.scope.forEachExtension((ExtensionBuilder extensionBuilder) {
+        MemberBuilder memberBuilder =
+            extensionBuilder.lookupLocalMember(name.name, setter: setter);
+        if (memberBuilder != null && !memberBuilder.isStatic) {
+          Extension extension = extensionBuilder.extension;
+          DartType onType;
+          DartType onTypeInstantiateToBounds;
+          List<DartType> inferredTypeArguments;
+          if (extensionBuilder.extension.typeParameters.isEmpty) {
+            onTypeInstantiateToBounds =
+                onType = extensionBuilder.extension.onType;
+            inferredTypeArguments = const <DartType>[];
+          } else {
+            List<TypeParameter> typeParameters =
+                extensionBuilder.extension.typeParameters;
+            inferredTypeArguments = _inferExtensionTypeArguments(
+                extensionBuilder.extension.typeParameters,
+                extensionBuilder.extension.onType,
+                receiverType);
+            Substitution inferredSubstitution =
+                Substitution.fromPairs(typeParameters, inferredTypeArguments);
+
+            for (int index = 0; index < typeParameters.length; index++) {
+              TypeParameter typeParameter = typeParameters[index];
+              DartType typeArgument = inferredTypeArguments[index];
+              DartType bound =
+                  inferredSubstitution.substituteType(typeParameter.bound);
+              if (!typeSchemaEnvironment.isSubtypeOf(typeArgument, bound)) {
+                return;
+              }
+            }
+            onType = inferredSubstitution
+                .substituteType(extensionBuilder.extension.onType);
+            List<DartType> instantiateToBoundTypeArguments =
+                calculateBounds(typeParameters, coreTypes.objectClass);
+            Substitution instantiateToBoundsSubstitution =
+                Substitution.fromPairs(
+                    typeParameters, instantiateToBoundTypeArguments);
+            onTypeInstantiateToBounds = instantiateToBoundsSubstitution
+                .substituteType(extensionBuilder.extension.onType);
+          }
+
+          if (typeSchemaEnvironment.isSubtypeOf(receiverType, onType)) {
+            ExtensionAccessCandidate candidate = new ExtensionAccessCandidate(
+                extension,
+                onType,
+                onTypeInstantiateToBounds,
+                new ObjectAccessTarget.extensionMember(
+                    memberBuilder.procedure,
+                    memberBuilder.extensionTearOff,
+                    memberBuilder.kind,
+                    inferredTypeArguments));
+            if (noneMoreSpecific.isNotEmpty) {
+              bool isMostSpecific = true;
+              for (ExtensionAccessCandidate other in noneMoreSpecific) {
+                bool isMoreSpecific =
+                    candidate.isMoreSpecificThan(typeSchemaEnvironment, other);
+                if (isMoreSpecific != true) {
+                  isMostSpecific = false;
+                  break;
+                }
+              }
+              if (isMostSpecific) {
+                bestSoFar = candidate;
+                noneMoreSpecific.clear();
+              } else {
+                noneMoreSpecific.add(candidate);
+              }
+            } else if (bestSoFar == null) {
+              bestSoFar = candidate;
+            } else {
+              bool isMoreSpecific = candidate.isMoreSpecificThan(
+                  typeSchemaEnvironment, bestSoFar);
+              if (isMoreSpecific == true) {
+                bestSoFar = candidate;
+              } else if (isMoreSpecific == null) {
+                noneMoreSpecific.add(bestSoFar);
+                noneMoreSpecific.add(candidate);
+                bestSoFar = null;
+              }
+            }
+          }
+        }
+      });
+      if (bestSoFar != null) {
+        target = bestSoFar.target;
+      } else {
+        // TODO(johnniwinther): Report a better error message when more than
+        // one potential targets were found.
+      }
     }
 
     if (!isTopLevel &&
-        interfaceMember == null &&
+        target.isUnresolved &&
         receiverType is! DynamicType &&
         receiverType is! InvalidType &&
         !(receiverType == coreTypes.functionClass.rawType &&
@@ -783,55 +901,58 @@
               fileOffset,
               length)));
     }
-    return interfaceMember;
+    return target;
   }
 
   /// Finds a member of [receiverType] called [name] and records it in
   /// [methodInvocation].
-  Object findMethodInvocationMember(
+  ObjectAccessTarget findMethodInvocationMember(
       DartType receiverType, InvocationExpression methodInvocation,
       {bool instrumented: true}) {
     // TODO(paulberry): could we add getters to InvocationExpression to make
     // these is-checks unnecessary?
     if (methodInvocation is MethodInvocation) {
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget interfaceTarget = findInterfaceMember(
           receiverType, methodInvocation.name, methodInvocation.fileOffset,
           errorTemplate: templateUndefinedMethod,
           expression: methodInvocation,
           receiver: methodInvocation.receiver,
-          instrumented: instrumented);
-      if (receiverType == const DynamicType() && interfaceMember is Procedure) {
-        Arguments arguments = methodInvocation.arguments;
-        FunctionNode signature = interfaceMember.function;
-        if (arguments.positional.length < signature.requiredParameterCount ||
-            arguments.positional.length >
-                signature.positionalParameters.length) {
-          return null;
-        }
-        for (kernel.NamedExpression argument in arguments.named) {
-          if (!signature.namedParameters
-              .any((declaration) => declaration.name == argument.name)) {
-            return null;
+          instrumented: instrumented,
+          includeExtensionMethods: true);
+      if (interfaceTarget.isInstanceMember) {
+        Member interfaceMember = interfaceTarget.member;
+        if (receiverType == const DynamicType() &&
+            interfaceMember is Procedure) {
+          Arguments arguments = methodInvocation.arguments;
+          FunctionNode signature = interfaceMember.function;
+          if (arguments.positional.length < signature.requiredParameterCount ||
+              arguments.positional.length >
+                  signature.positionalParameters.length) {
+            return const ObjectAccessTarget.unresolved();
+          }
+          for (kernel.NamedExpression argument in arguments.named) {
+            if (!signature.namedParameters
+                .any((declaration) => declaration.name == argument.name)) {
+              return const ObjectAccessTarget.unresolved();
+            }
+          }
+          if (instrumented && instrumentation != null) {
+            instrumentation.record(uri, methodInvocation.fileOffset, 'target',
+                new InstrumentationValueForMember(interfaceMember));
           }
         }
-        if (instrumented && instrumentation != null) {
-          instrumentation.record(uri, methodInvocation.fileOffset, 'target',
-              new InstrumentationValueForMember(interfaceMember));
-        }
-        methodInvocation.interfaceTarget = interfaceMember;
-      } else if (interfaceMember is Member) {
         methodInvocation.interfaceTarget = interfaceMember;
       }
-      return interfaceMember;
+      return interfaceTarget;
     } else if (methodInvocation is SuperMethodInvocation) {
       assert(receiverType != const DynamicType());
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget interfaceTarget = findInterfaceMember(
           receiverType, methodInvocation.name, methodInvocation.fileOffset,
           instrumented: instrumented);
-      if (interfaceMember is Member) {
-        methodInvocation.interfaceTarget = interfaceMember;
+      if (interfaceTarget.isInstanceMember) {
+        methodInvocation.interfaceTarget = interfaceTarget.member;
       }
-      return interfaceMember;
+      return interfaceTarget;
     } else {
       throw unhandled("${methodInvocation.runtimeType}",
           "findMethodInvocationMember", methodInvocation.fileOffset, uri);
@@ -840,34 +961,35 @@
 
   /// Finds a member of [receiverType] called [name], and if it is found,
   /// reports it through instrumentation and records it in [propertyGet].
-  Object findPropertyGetMember(DartType receiverType, Expression propertyGet,
+  ObjectAccessTarget findPropertyGetMember(
+      DartType receiverType, Expression propertyGet,
       {bool instrumented: true}) {
     // TODO(paulberry): could we add a common base class to PropertyGet and
     // SuperPropertyGet to make these is-checks unnecessary?
     if (propertyGet is PropertyGet) {
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget readTarget = findInterfaceMember(
           receiverType, propertyGet.name, propertyGet.fileOffset,
           errorTemplate: templateUndefinedGetter,
           expression: propertyGet,
           receiver: propertyGet.receiver,
           instrumented: instrumented);
-      if (interfaceMember is Member) {
+      if (readTarget.isInstanceMember) {
         if (instrumented &&
             instrumentation != null &&
             receiverType == const DynamicType()) {
           instrumentation.record(uri, propertyGet.fileOffset, 'target',
-              new InstrumentationValueForMember(interfaceMember));
+              new InstrumentationValueForMember(readTarget.member));
         }
-        propertyGet.interfaceTarget = interfaceMember;
+        propertyGet.interfaceTarget = readTarget.member;
       }
-      return interfaceMember;
+      return readTarget;
     } else if (propertyGet is SuperPropertyGet) {
       assert(receiverType != const DynamicType());
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget interfaceMember = findInterfaceMember(
           receiverType, propertyGet.name, propertyGet.fileOffset,
           instrumented: instrumented);
-      if (interfaceMember is Member) {
-        propertyGet.interfaceTarget = interfaceMember;
+      if (interfaceMember.isInstanceMember) {
+        propertyGet.interfaceTarget = interfaceMember.member;
       }
       return interfaceMember;
     } else {
@@ -878,33 +1000,35 @@
 
   /// Finds a member of [receiverType] called [name], and if it is found,
   /// reports it through instrumentation and records it in [propertySet].
-  Object findPropertySetMember(DartType receiverType, Expression propertySet,
+  ObjectAccessTarget findPropertySetMember(
+      DartType receiverType, Expression propertySet,
       {bool instrumented: true}) {
     if (propertySet is PropertySet) {
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget writeTarget = findInterfaceMember(
           receiverType, propertySet.name, propertySet.fileOffset,
           errorTemplate: templateUndefinedSetter,
           expression: propertySet,
           receiver: propertySet.receiver,
           setter: true,
-          instrumented: instrumented);
-      if (interfaceMember is Member) {
+          instrumented: instrumented,
+          includeExtensionMethods: true);
+      if (writeTarget.isInstanceMember) {
         if (instrumented &&
             instrumentation != null &&
             receiverType == const DynamicType()) {
           instrumentation.record(uri, propertySet.fileOffset, 'target',
-              new InstrumentationValueForMember(interfaceMember));
+              new InstrumentationValueForMember(writeTarget.member));
         }
-        propertySet.interfaceTarget = interfaceMember;
+        propertySet.interfaceTarget = writeTarget.member;
       }
-      return interfaceMember;
+      return writeTarget;
     } else if (propertySet is SuperPropertySet) {
       assert(receiverType != const DynamicType());
-      Object interfaceMember = findInterfaceMember(
+      ObjectAccessTarget interfaceMember = findInterfaceMember(
           receiverType, propertySet.name, propertySet.fileOffset,
           setter: true, instrumented: instrumented);
-      if (interfaceMember is Member) {
-        propertySet.interfaceTarget = interfaceMember;
+      if (interfaceMember.isInstanceMember) {
+        propertySet.interfaceTarget = interfaceMember.member;
       }
       return interfaceMember;
     } else {
@@ -913,56 +1037,259 @@
     }
   }
 
-  FunctionType getCalleeFunctionType(DartType calleeType, bool followCall) {
+  /// Returns the type of [target] when accessed as a getter on [receiverType].
+  ///
+  /// For instance
+  ///
+  ///    class Class<T> {
+  ///      T method() {}
+  ///      T getter => null;
+  ///    }
+  ///
+  ///    Class<int> c = ...
+  ///    c.method; // The getter type is `int Function()`.
+  ///    c.getter; // The getter type is `int`.
+  ///
+  DartType getGetterType(ObjectAccessTarget target, DartType receiverType) {
+    switch (target.kind) {
+      case ObjectAccessTargetKind.callFunction:
+        return receiverType;
+      case ObjectAccessTargetKind.unresolved:
+        return const DynamicType();
+      case ObjectAccessTargetKind.instanceMember:
+        return getGetterTypeForMemberTarget(target.member, receiverType);
+      case ObjectAccessTargetKind.extensionMember:
+        switch (target.extensionMethodKind) {
+          case ProcedureKind.Method:
+          case ProcedureKind.Operator:
+            FunctionType functionType = target.member.function.functionType;
+            List<TypeParameter> extensionTypeParameters = functionType
+                .typeParameters
+                .take(target.inferredExtensionTypeArguments.length)
+                .toList();
+            Substitution substitution = Substitution.fromPairs(
+                extensionTypeParameters, target.inferredExtensionTypeArguments);
+            return substitution.substituteType(new FunctionType(
+                functionType.positionalParameters.skip(1).toList(),
+                functionType.returnType,
+                namedParameters: functionType.namedParameters,
+                typeParameters: functionType.typeParameters
+                    .skip(target.inferredExtensionTypeArguments.length)
+                    .toList(),
+                requiredParameterCount:
+                    functionType.requiredParameterCount - 1));
+          case ProcedureKind.Getter:
+            FunctionType functionType = target.member.function.functionType;
+            List<TypeParameter> extensionTypeParameters = functionType
+                .typeParameters
+                .take(target.inferredExtensionTypeArguments.length)
+                .toList();
+            Substitution substitution = Substitution.fromPairs(
+                extensionTypeParameters, target.inferredExtensionTypeArguments);
+            return substitution.substituteType(functionType.returnType);
+          case ProcedureKind.Setter:
+          case ProcedureKind.Factory:
+            break;
+        }
+    }
+    throw unhandled('$target', 'getGetterType', null, null);
+  }
+
+  /// Returns the getter type of [member] on a receiver of type [receiverType].
+  ///
+  /// For instance
+  ///
+  ///    class Class<T> {
+  ///      T method() {}
+  ///      T getter => null;
+  ///    }
+  ///
+  ///    Class<int> c = ...
+  ///    c.method; // The getter type is `int Function()`.
+  ///    c.getter; // The getter type is `int`.
+  ///
+  DartType getGetterTypeForMemberTarget(
+      Member interfaceMember, DartType receiverType) {
+    Class memberClass = interfaceMember.enclosingClass;
+    assert(
+        interfaceMember is kernel.Field || interfaceMember is kernel.Procedure,
+        "Unexpected interface member $interfaceMember.");
+    DartType calleeType = interfaceMember.getterType;
+    if (memberClass.typeParameters.isNotEmpty) {
+      receiverType = resolveTypeParameter(receiverType);
+      if (receiverType is InterfaceType) {
+        InterfaceType castedType =
+            classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
+        calleeType = Substitution.fromInterfaceType(castedType)
+            .substituteType(calleeType);
+      }
+    }
+    return calleeType;
+  }
+
+  /// Returns the type of [target] when accessed as an invocation on
+  /// [receiverType].
+  ///
+  /// If the target is known not to be invokable [unknownFunction] is returned.
+  ///
+  /// For instance
+  ///
+  ///    class Class<T> {
+  ///      T method() {}
+  ///      T Function() getter1 => null;
+  ///      T getter2 => null;
+  ///    }
+  ///
+  ///    Class<int> c = ...
+  ///    c.method; // The getter type is `int Function()`.
+  ///    c.getter1; // The getter type is `int Function()`.
+  ///    c.getter2; // The getter type is [unknownFunction].
+  ///
+  FunctionType getFunctionType(
+      ObjectAccessTarget target, DartType receiverType, bool followCall) {
+    switch (target.kind) {
+      case ObjectAccessTargetKind.callFunction:
+        return _getFunctionType(receiverType, followCall);
+      case ObjectAccessTargetKind.unresolved:
+        return unknownFunction;
+      case ObjectAccessTargetKind.instanceMember:
+        return _getFunctionType(
+            getGetterTypeForMemberTarget(target.member, receiverType),
+            followCall);
+      case ObjectAccessTargetKind.extensionMember:
+        switch (target.extensionMethodKind) {
+          case ProcedureKind.Method:
+          case ProcedureKind.Operator:
+            return target.member.function.functionType;
+          case ProcedureKind.Getter:
+            // TODO(johnniwinther): Handle implicit .call on extension getter.
+            return _getFunctionType(target.member.function.returnType, false);
+          case ProcedureKind.Setter:
+          case ProcedureKind.Factory:
+            break;
+        }
+    }
+    throw unhandled('$target', 'getFunctionType', null, null);
+  }
+
+  /// Returns the type of the 'key' parameter in an []= implementation.
+  ///
+  /// For instance
+  ///
+  ///    class Class<K, V> {
+  ///      void operator []=(K key, V value) {}
+  ///    }
+  ///
+  ///    extension Extension<K, V> on Class<K, V> {
+  ///      void operator []=(K key, V value) {}
+  ///    }
+  ///
+  ///    new Class<int, String>()[0] = 'foo';     // The key type is `int`.
+  ///    Extension<int, String>(null)[0] = 'foo'; // The key type is `int`.
+  ///
+  DartType getIndexSetKeyType(
+      ObjectAccessTarget target, DartType receiverType) {
+    switch (target.kind) {
+      case ObjectAccessTargetKind.instanceMember:
+        FunctionType functionType = _getFunctionType(
+            getGetterTypeForMemberTarget(target.member, receiverType), false);
+        if (functionType.positionalParameters.length >= 1) {
+          return functionType.positionalParameters[0];
+        }
+        break;
+      case ObjectAccessTargetKind.extensionMember:
+        switch (target.extensionMethodKind) {
+          case ProcedureKind.Operator:
+            FunctionType functionType = target.member.function.functionType;
+            if (functionType.positionalParameters.length >= 2) {
+              DartType indexType = functionType.positionalParameters[1];
+              if (functionType.typeParameters.isNotEmpty) {
+                Substitution substitution = Substitution.fromPairs(
+                    functionType.typeParameters,
+                    target.inferredExtensionTypeArguments);
+                return substitution.substituteType(indexType);
+              }
+              return indexType;
+            }
+            break;
+          default:
+            throw unhandled('$target', 'getFunctionType', null, null);
+        }
+        break;
+      case ObjectAccessTargetKind.callFunction:
+      case ObjectAccessTargetKind.unresolved:
+        break;
+    }
+    return const UnknownType();
+  }
+
+  /// Returns the type of the 'value' parameter in an []= implementation.
+  ///
+  /// For instance
+  ///
+  ///    class Class<K, V> {
+  ///      void operator []=(K key, V value) {}
+  ///    }
+  ///
+  ///    extension Extension<K, V> on Class<K, V> {
+  ///      void operator []=(K key, V value) {}
+  ///    }
+  ///
+  ///    new Class<int, String>()[0] = 'foo';     // The value type is `String`.
+  ///    Extension<int, String>(null)[0] = 'foo'; // The value type is `String`.
+  ///
+  DartType getIndexSetValueType(
+      ObjectAccessTarget target, DartType receiverType) {
+    switch (target.kind) {
+      case ObjectAccessTargetKind.instanceMember:
+        FunctionType functionType = _getFunctionType(
+            getGetterTypeForMemberTarget(target.member, receiverType), false);
+        if (functionType.positionalParameters.length >= 2) {
+          return functionType.positionalParameters[1];
+        }
+        break;
+      case ObjectAccessTargetKind.extensionMember:
+        switch (target.extensionMethodKind) {
+          case ProcedureKind.Operator:
+            FunctionType functionType = target.member.function.functionType;
+            if (functionType.positionalParameters.length >= 3) {
+              DartType indexType = functionType.positionalParameters[2];
+              if (functionType.typeParameters.isNotEmpty) {
+                Substitution substitution = Substitution.fromPairs(
+                    functionType.typeParameters,
+                    target.inferredExtensionTypeArguments);
+                return substitution.substituteType(indexType);
+              }
+              return indexType;
+            }
+            break;
+          default:
+            throw unhandled('$target', 'getFunctionType', null, null);
+        }
+        break;
+      case ObjectAccessTargetKind.callFunction:
+      case ObjectAccessTargetKind.unresolved:
+        break;
+    }
+    return const UnknownType();
+  }
+
+  FunctionType _getFunctionType(DartType calleeType, bool followCall) {
     if (calleeType is FunctionType) {
       return calleeType;
     } else if (followCall && calleeType is InterfaceType) {
       Member member =
           _getInterfaceMember(calleeType.classNode, callName, false, -1);
-      DartType callType = getCalleeType(member, calleeType);
-      if (callType is FunctionType) {
-        return callType;
+      if (member != null) {
+        DartType callType = getGetterTypeForMemberTarget(member, calleeType);
+        if (callType is FunctionType) {
+          return callType;
+        }
       }
     }
     return unknownFunction;
   }
 
-  DartType getCalleeType(Object interfaceMember, DartType receiverType) {
-    if (identical(interfaceMember, 'call')) {
-      return receiverType;
-    } else if (interfaceMember == null) {
-      return const DynamicType();
-    } else if (interfaceMember is Member) {
-      Class memberClass = interfaceMember.enclosingClass;
-      DartType calleeType;
-      if (interfaceMember is Procedure) {
-        if (interfaceMember.kind == ProcedureKind.Getter) {
-          calleeType = interfaceMember.function.returnType;
-        } else {
-          calleeType = interfaceMember.function.functionType;
-        }
-      } else if (interfaceMember is Field) {
-        calleeType = interfaceMember.type;
-      } else {
-        throw unhandled(interfaceMember.runtimeType.toString(), 'getCalleeType',
-            null, null);
-      }
-      if (memberClass.typeParameters.isNotEmpty) {
-        receiverType = resolveTypeParameter(receiverType);
-        if (receiverType is InterfaceType) {
-          InterfaceType castedType =
-              classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
-          calleeType = Substitution.fromInterfaceType(castedType)
-              .substituteType(calleeType);
-        }
-      }
-      return calleeType;
-    } else {
-      throw unhandled(
-          interfaceMember.runtimeType.toString(), 'getCalleeType', null, null);
-    }
-  }
-
   DartType getDerivedTypeArgumentOf(DartType type, Class class_) {
     if (type is InterfaceType) {
       InterfaceType typeAsInstanceOfClass =
@@ -987,41 +1314,60 @@
     return member;
   }
 
-  DartType getSetterType(Object interfaceMember, DartType receiverType) {
-    if (interfaceMember is FunctionType) {
-      return interfaceMember;
-    } else if (interfaceMember == null) {
-      return const DynamicType();
-    } else if (interfaceMember is Member) {
-      Class memberClass = interfaceMember.enclosingClass;
-      DartType setterType;
-      if (interfaceMember is Procedure) {
-        assert(interfaceMember.kind == ProcedureKind.Setter);
-        List<VariableDeclaration> setterParameters =
-            interfaceMember.function.positionalParameters;
-        setterType = setterParameters.length > 0
-            ? setterParameters[0].type
-            : const DynamicType();
-      } else if (interfaceMember is Field) {
-        setterType = interfaceMember.type;
-      } else {
-        throw unhandled(interfaceMember.runtimeType.toString(), 'getSetterType',
-            null, null);
-      }
-      if (memberClass.typeParameters.isNotEmpty) {
-        receiverType = resolveTypeParameter(receiverType);
-        if (receiverType is InterfaceType) {
-          InterfaceType castedType =
-              classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
-          setterType = Substitution.fromInterfaceType(castedType)
-              .substituteType(setterType);
+  DartType getSetterType(ObjectAccessTarget target, DartType receiverType) {
+    switch (target.kind) {
+      case ObjectAccessTargetKind.unresolved:
+        return const DynamicType();
+      case ObjectAccessTargetKind.instanceMember:
+        Member interfaceMember = target.member;
+        Class memberClass = interfaceMember.enclosingClass;
+        DartType setterType;
+        if (interfaceMember is Procedure) {
+          assert(interfaceMember.kind == ProcedureKind.Setter);
+          List<VariableDeclaration> setterParameters =
+              interfaceMember.function.positionalParameters;
+          setterType = setterParameters.length > 0
+              ? setterParameters[0].type
+              : const DynamicType();
+        } else if (interfaceMember is Field) {
+          setterType = interfaceMember.type;
+        } else {
+          throw unhandled(interfaceMember.runtimeType.toString(),
+              'getSetterType', null, null);
         }
-      }
-      return setterType;
-    } else {
-      throw unhandled(
-          interfaceMember.runtimeType.toString(), 'getSetterType', null, null);
+        if (memberClass.typeParameters.isNotEmpty) {
+          receiverType = resolveTypeParameter(receiverType);
+          if (receiverType is InterfaceType) {
+            InterfaceType castedType =
+                classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
+            setterType = Substitution.fromInterfaceType(castedType)
+                .substituteType(setterType);
+          }
+        }
+        return setterType;
+      case ObjectAccessTargetKind.extensionMember:
+        switch (target.extensionMethodKind) {
+          case ProcedureKind.Setter:
+            FunctionType functionType = target.member.function.functionType;
+            List<TypeParameter> extensionTypeParameters = functionType
+                .typeParameters
+                .take(target.inferredExtensionTypeArguments.length)
+                .toList();
+            Substitution substitution = Substitution.fromPairs(
+                extensionTypeParameters, target.inferredExtensionTypeArguments);
+            return substitution
+                .substituteType(functionType.positionalParameters[1]);
+          case ProcedureKind.Method:
+          case ProcedureKind.Getter:
+          case ProcedureKind.Factory:
+          case ProcedureKind.Operator:
+            break;
+        }
+        // TODO(johnniwinther): Compute the right setter type.
+        return const DynamicType();
+      case ObjectAccessTargetKind.callFunction:
     }
+    throw unhandled(target.runtimeType.toString(), 'getSetterType', null, null);
   }
 
   DartType getTypeArgumentOf(DartType type, Class class_) {
@@ -1092,15 +1438,16 @@
   /// expression.
   Expression handlePropertyGetContravariance(
       Expression receiver,
-      Object interfaceMember,
+      ObjectAccessTarget readTarget,
       PropertyGet desugaredGet,
       Expression expression,
       DartType inferredType,
       int fileOffset) {
     bool checkReturn = false;
     if (receiver != null &&
-        interfaceMember != null &&
+        readTarget.isInstanceMember &&
         receiver is! ThisExpression) {
+      Member interfaceMember = readTarget.member;
       if (interfaceMember is Procedure) {
         checkReturn = returnedTypeParametersOccurNonCovariantly(
             interfaceMember.enclosingClass,
@@ -1144,12 +1491,13 @@
   ///
   /// [typeContext] is the expected type of the expression, based on surrounding
   /// code.  [typeNeeded] indicates whether it is necessary to compute the
-  /// actual type of the expression.  If [typeNeeded] is `true`, the actual type
-  /// of the expression is returned; otherwise `null` is returned.
+  /// actual type of the expression.  If [typeNeeded] is `true`,
+  /// [ExpressionInferenceResult.inferredType] is the actual type of the
+  /// expression; otherwise `null`.
   ///
   /// Derived classes should override this method with logic that dispatches on
   /// the expression type and calls the appropriate specialized "infer" method.
-  DartType inferExpression(
+  ExpressionInferenceResult inferExpression(
       kernel.Expression expression, DartType typeContext, bool typeNeeded,
       {bool isVoidAllowed});
 
@@ -1162,9 +1510,10 @@
     assert(closureContext == null);
     assert(!isTopLevel);
     this.helper = helper;
-    DartType actualType =
+    ExpressionInferenceResult result =
         inferExpression(initializer, context, true, isVoidAllowed: true);
-    ensureAssignable(context, actualType, initializer, initializer.fileOffset,
+    ensureAssignable(
+        context, result.inferredType, initializer, initializer.fileOffset,
         isVoidAllowed: context is VoidType);
     this.helper = null;
   }
@@ -1180,14 +1529,105 @@
     this.helper = null;
   }
 
-  /// Performs the type inference steps that are shared by all kinds of
-  /// invocations (constructors, instance methods, and static methods).
-  ExpressionInferenceResult inferInvocation(DartType typeContext, int offset,
+  DartType inferInvocation(DartType typeContext, int offset,
       FunctionType calleeType, DartType returnType, Arguments arguments,
       {bool isOverloadedArithmeticOperator: false,
       DartType receiverType,
       bool skipTypeArgumentInference: false,
-      bool isConst: false}) {
+      bool isConst: false,
+      bool isImplicitExtensionMember: false}) {
+    int extensionTypeParameterCount = getExtensionTypeParameterCount(arguments);
+    if (extensionTypeParameterCount != 0) {
+      return _inferGenericExtensionMethodInvocation(extensionTypeParameterCount,
+          typeContext, offset, calleeType, returnType, arguments,
+          isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+          receiverType: receiverType,
+          skipTypeArgumentInference: skipTypeArgumentInference,
+          isConst: isConst,
+          isImplicitExtensionMember: isImplicitExtensionMember);
+    }
+    return _inferInvocation(
+        typeContext, offset, calleeType, returnType, arguments,
+        isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+        receiverType: receiverType,
+        skipTypeArgumentInference: skipTypeArgumentInference,
+        isConst: isConst,
+        isImplicitExtensionMember: isImplicitExtensionMember);
+  }
+
+  DartType _inferGenericExtensionMethodInvocation(
+      int extensionTypeParameterCount,
+      DartType typeContext,
+      int offset,
+      FunctionType calleeType,
+      DartType returnType,
+      Arguments arguments,
+      {bool isOverloadedArithmeticOperator: false,
+      DartType receiverType,
+      bool skipTypeArgumentInference: false,
+      bool isConst: false,
+      bool isImplicitExtensionMember: false}) {
+    FunctionType extensionFunctionType = new FunctionType(
+        [calleeType.positionalParameters.first], const DynamicType(),
+        requiredParameterCount: 1,
+        typeParameters: calleeType.typeParameters
+            .take(extensionTypeParameterCount)
+            .toList());
+    Arguments extensionArguments = helper.forest.createArguments(
+        arguments.fileOffset, [arguments.positional.first],
+        types: getExplicitExtensionTypeArguments(arguments));
+    _inferInvocation(const UnknownType(), offset, extensionFunctionType,
+        extensionFunctionType.returnType, extensionArguments,
+        skipTypeArgumentInference: skipTypeArgumentInference,
+        receiverType: receiverType,
+        isImplicitExtensionMember: isImplicitExtensionMember);
+    Substitution extensionSubstitution = Substitution.fromPairs(
+        extensionFunctionType.typeParameters, extensionArguments.types);
+
+    List<TypeParameter> targetTypeParameters = const <TypeParameter>[];
+    if (calleeType.typeParameters.length > extensionTypeParameterCount) {
+      targetTypeParameters =
+          calleeType.typeParameters.skip(extensionTypeParameterCount).toList();
+    }
+    FunctionType targetFunctionType = new FunctionType(
+        calleeType.positionalParameters.skip(1).toList(), calleeType.returnType,
+        requiredParameterCount: calleeType.requiredParameterCount - 1,
+        namedParameters: calleeType.namedParameters,
+        typeParameters: targetTypeParameters);
+    targetFunctionType =
+        extensionSubstitution.substituteType(targetFunctionType);
+    DartType targetReturnType =
+        extensionSubstitution.substituteType(returnType);
+    Arguments targetArguments = helper.forest.createArguments(
+        arguments.fileOffset, arguments.positional.skip(1).toList(),
+        named: arguments.named, types: getExplicitTypeArguments(arguments));
+    DartType inferredType = _inferInvocation(typeContext, offset,
+        targetFunctionType, targetReturnType, targetArguments,
+        isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+        skipTypeArgumentInference: skipTypeArgumentInference,
+        isConst: isConst);
+    arguments.positional.clear();
+    arguments.positional.addAll(extensionArguments.positional);
+    arguments.positional.addAll(targetArguments.positional);
+    setParents(arguments.positional, arguments);
+    // The `targetArguments.named` is the same list as `arguments.named` so
+    // we just need to ensure that parent relations are realigned.
+    setParents(arguments.named, arguments);
+    arguments.types.clear();
+    arguments.types.addAll(extensionArguments.types);
+    arguments.types.addAll(targetArguments.types);
+    return inferredType;
+  }
+
+  /// Performs the type inference steps that are shared by all kinds of
+  /// invocations (constructors, instance methods, and static methods).
+  DartType _inferInvocation(DartType typeContext, int offset,
+      FunctionType calleeType, DartType returnType, Arguments arguments,
+      {bool isOverloadedArithmeticOperator: false,
+      DartType receiverType,
+      bool skipTypeArgumentInference: false,
+      bool isConst: false,
+      bool isImplicitExtensionMember: false}) {
     lastInferredSubstitution = null;
     lastCalleeType = null;
     List<TypeParameter> calleeTypeParameters = calleeType.typeParameters;
@@ -1250,19 +1690,29 @@
       DartType inferredFormalType = substitution != null
           ? substitution.substituteType(formalType)
           : formalType;
-      DartType expressionType = inferExpression(
-          expression,
-          inferredFormalType,
-          inferenceNeeded ||
-              isOverloadedArithmeticOperator ||
-              typeChecksNeeded);
+      DartType inferredType;
+      if (isImplicitExtensionMember && i == 1) {
+        assert(
+            receiverType != null,
+            "No receiver type provided for implicit extension member "
+            "invocation.");
+        inferredType = receiverType;
+      } else {
+        ExpressionInferenceResult result = inferExpression(
+            expression,
+            inferredFormalType,
+            inferenceNeeded ||
+                isOverloadedArithmeticOperator ||
+                typeChecksNeeded);
+        inferredType = result.inferredType;
+      }
       if (inferenceNeeded || typeChecksNeeded) {
         formalTypes.add(formalType);
-        actualTypes.add(expressionType);
+        actualTypes.add(inferredType);
       }
       if (isOverloadedArithmeticOperator) {
         returnType = typeSchemaEnvironment.getTypeOfOverloadedArithmetic(
-            receiverType, expressionType);
+            receiverType, inferredType);
       }
     });
 
@@ -1356,11 +1806,11 @@
     inferredType = substitution == null
         ? returnType
         : substitution.substituteType(returnType);
-    return new ExpressionInferenceResult(null, inferredType);
+    return inferredType;
   }
 
-  ExpressionInferenceResult inferLocalFunction(FunctionNode function,
-      DartType typeContext, int fileOffset, DartType returnContext) {
+  DartType inferLocalFunction(FunctionNode function, DartType typeContext,
+      int fileOffset, DartType returnContext) {
     bool hasImplicitReturnType = false;
     if (returnContext == null) {
       hasImplicitReturnType = true;
@@ -1493,7 +1943,7 @@
       function.returnType = inferredReturnType;
     }
     this.closureContext = oldClosureContext;
-    return new ExpressionInferenceResult(null, function.functionType);
+    return function.functionType;
   }
 
   @override
@@ -1523,6 +1973,29 @@
     }
   }
 
+  StaticInvocation transformExtensionMethodInvocation(ObjectAccessTarget target,
+      Expression expression, Expression receiver, Arguments arguments) {
+    assert(target.isExtensionMember);
+    Procedure procedure = target.member;
+    Expression replacement;
+    expression.parent.replaceChild(
+        expression,
+        replacement = helper.forest.createStaticInvocation(
+            expression.fileOffset,
+            target.member,
+            arguments = helper.forest.createArgumentsForExtensionMethod(
+                arguments.fileOffset,
+                target.inferredExtensionTypeArguments.length,
+                procedure.function.typeParameters.length -
+                    target.inferredExtensionTypeArguments.length,
+                receiver,
+                extensionTypeArguments: target.inferredExtensionTypeArguments,
+                positionalArguments: arguments.positional,
+                namedArguments: arguments.named,
+                typeArguments: arguments.types)));
+    return replacement;
+  }
+
   /// Performs the core type inference algorithm for method invocations (this
   /// handles both null-aware and non-null-aware method invocations).
   ExpressionInferenceResult inferMethodInvocation(
@@ -1533,28 +2006,39 @@
       DartType typeContext,
       {VariableDeclaration receiverVariable,
       MethodInvocation desugaredInvocation,
-      Object interfaceMember,
+      ObjectAccessTarget target,
       Name methodName,
       Arguments arguments}) {
+    assert(desugaredInvocation == null || target == null);
+    assert(desugaredInvocation != null || target != null);
     // First infer the receiver so we can look up the method that was invoked.
-    DartType receiverType = receiver == null
-        ? thisType
-        : inferExpression(receiver, const UnknownType(), true);
+    DartType receiverType;
+    if (receiver == null) {
+      receiverType = thisType;
+    } else {
+      ExpressionInferenceResult result =
+          inferExpression(receiver, const UnknownType(), true);
+      receiverType = result.inferredType;
+    }
     receiverVariable?.type = receiverType;
     if (desugaredInvocation != null) {
-      interfaceMember =
-          findMethodInvocationMember(receiverType, desugaredInvocation);
+      target = findMethodInvocationMember(receiverType, desugaredInvocation);
       methodName = desugaredInvocation.name;
       arguments = desugaredInvocation.arguments;
     }
-    bool isOverloadedArithmeticOperator = interfaceMember is Procedure &&
+    assert(
+        target != null,
+        "No target for ${expression} with desugared "
+        "invocation ${desugaredInvocation}.");
+    bool isOverloadedArithmeticOperator = target.isInstanceMember &&
+        target.member is Procedure &&
         typeSchemaEnvironment.isOverloadedArithmeticOperatorAndType(
-            interfaceMember, receiverType);
-    DartType calleeType = getCalleeType(interfaceMember, receiverType);
+            target.member, receiverType);
+    DartType calleeType = getGetterType(target, receiverType);
     FunctionType functionType =
-        getCalleeFunctionType(calleeType, !isImplicitCall);
+        getFunctionType(target, receiverType, !isImplicitCall);
 
-    if (interfaceMember != null &&
+    if (!target.isUnresolved &&
         calleeType is! DynamicType &&
         calleeType != coreTypes.functionClass.rawType &&
         identical(functionType, unknownFunction)) {
@@ -1562,32 +2046,34 @@
       kernel.Expression error = helper.wrapInProblem(expression,
           templateInvokeNonFunction.withArguments(methodName.name), noLength);
       parent?.replaceChild(expression, error);
-      return new ExpressionInferenceResult(null, const DynamicType());
+      return const ExpressionInferenceResult(const DynamicType());
     }
     MethodContravarianceCheckKind checkKind = preCheckInvocationContravariance(
         receiver,
         receiverType,
-        interfaceMember,
+        target,
         desugaredInvocation,
         arguments,
         expression);
-    ExpressionInferenceResult inferenceResult = inferInvocation(typeContext,
-        fileOffset, functionType, functionType.returnType, arguments,
+    StaticInvocation replacement;
+    if (target.isExtensionMember) {
+      replacement = transformExtensionMethodInvocation(
+          target, expression, receiver, arguments);
+      arguments = replacement.arguments;
+    }
+    DartType inferredType = inferInvocation(typeContext, fileOffset,
+        functionType, functionType.returnType, arguments,
         isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
-        receiverType: receiverType);
-    DartType inferredType = inferenceResult.type;
+        receiverType: receiverType,
+        isImplicitExtensionMember: target.isExtensionMember);
     if (methodName.name == '==') {
       inferredType = coreTypes.boolClass.rawType;
     }
     handleInvocationContravariance(checkKind, desugaredInvocation, arguments,
         expression, inferredType, functionType, fileOffset);
-    if (!identical(interfaceMember, 'call')) {
-      if (isImplicitCall &&
-          interfaceMember != null &&
-          !(interfaceMember is Procedure &&
-              interfaceMember.kind == ProcedureKind.Method) &&
-          receiverType is! DynamicType &&
-          receiverType != typeSchemaEnvironment.rawFunctionType) {
+    if (isImplicitCall && target.isInstanceMember) {
+      Member member = target.member;
+      if (!(member is Procedure && member.kind == ProcedureKind.Method)) {
         TreeNode parent = expression.parent;
         Expression errorNode = helper.wrapInProblem(
             expression,
@@ -1598,8 +2084,11 @@
     }
 
     // If [arguments] were inferred, check them.
-    // TODO(dmitryas): Figure out why [library] is sometimes null.
-    if (library != null) {
+    // TODO(dmitryas): Figure out why [library] is sometimes null? Answer:
+    // because top level inference never got a library. This has changed so
+    // we always have a library. Should we still skip this for top level
+    // inference?
+    if (!isTopLevel) {
       // [actualReceiverType], [interfaceTarget], and [actualMethodName] below
       // are for a workaround for the cases like the following:
       //
@@ -1615,7 +2104,7 @@
         actualMethodName = callName;
       } else {
         actualReceiverType = receiverType;
-        interfaceTarget = interfaceMember is Member ? interfaceMember : null;
+        interfaceTarget = target.isInstanceMember ? target.member : null;
         actualMethodName = methodName;
       }
       library.checkBoundsInMethodInvocation(
@@ -1631,7 +2120,7 @@
           inferred: getExplicitTypeArguments(arguments) == null);
     }
 
-    return new ExpressionInferenceResult(null, inferredType);
+    return new ExpressionInferenceResult(inferredType, replacement);
   }
 
   @override
@@ -1640,53 +2129,97 @@
     assert(closureContext == null);
     this.helper = helper;
     assert(declaredType != null);
-    DartType actualType = inferExpression(initializer, declaredType, true);
+    ExpressionInferenceResult result =
+        inferExpression(initializer, declaredType, true);
     ensureAssignable(
-        declaredType, actualType, initializer, initializer.fileOffset);
+        declaredType, result.inferredType, initializer, initializer.fileOffset);
     this.helper = null;
   }
 
   /// Performs the core type inference algorithm for property gets (this handles
   /// both null-aware and non-null-aware property gets).
-  void inferPropertyGet(Expression expression, Expression receiver,
-      int fileOffset, DartType typeContext,
+  ExpressionInferenceResult inferPropertyGet(Expression expression,
+      Expression receiver, int fileOffset, DartType typeContext,
       {VariableDeclaration receiverVariable,
       PropertyGet desugaredGet,
-      Object interfaceMember,
-      Name propertyName}) {
+      ObjectAccessTarget readTarget,
+      Name propertyName,
+      bool allowExtensionMethods: false}) {
     // First infer the receiver so we can look up the getter that was invoked.
     DartType receiverType;
     if (receiver == null) {
       receiverType = thisType;
     } else {
-      inferExpression(receiver, const UnknownType(), true);
-      receiverType = getInferredType(receiver, this);
+      ExpressionInferenceResult result =
+          inferExpression(receiver, const UnknownType(), true);
+      receiverType = result.inferredType;
     }
     receiverVariable?.type = receiverType;
     propertyName ??= desugaredGet.name;
     if (desugaredGet != null) {
-      interfaceMember = findInterfaceMember(
-          receiverType, propertyName, fileOffset,
+      readTarget = findInterfaceMember(receiverType, propertyName, fileOffset,
           errorTemplate: templateUndefinedGetter,
           expression: expression,
-          receiver: receiver);
-      if (interfaceMember is Member) {
+          receiver: receiver,
+          includeExtensionMethods: allowExtensionMethods);
+      if (readTarget.isInstanceMember) {
         if (instrumentation != null && receiverType == const DynamicType()) {
           instrumentation.record(uri, desugaredGet.fileOffset, 'target',
-              new InstrumentationValueForMember(interfaceMember));
+              new InstrumentationValueForMember(readTarget.member));
         }
-        desugaredGet.interfaceTarget = interfaceMember;
+        desugaredGet.interfaceTarget = readTarget.member;
       }
     }
-    DartType inferredType = getCalleeType(interfaceMember, receiverType);
+    DartType inferredType = getGetterType(readTarget, receiverType);
     Expression replacedExpression = handlePropertyGetContravariance(receiver,
-        interfaceMember, desugaredGet, expression, inferredType, fileOffset);
-    if ((interfaceMember is Procedure &&
-        interfaceMember.kind == ProcedureKind.Method)) {
-      inferredType =
-          instantiateTearOff(inferredType, typeContext, replacedExpression);
+        readTarget, desugaredGet, expression, inferredType, fileOffset);
+    Expression replacement;
+    if (readTarget.isInstanceMember) {
+      Member member = readTarget.member;
+      if (member is Procedure && member.kind == ProcedureKind.Method) {
+        inferredType =
+            instantiateTearOff(inferredType, typeContext, replacedExpression);
+      }
+    } else if (readTarget.isExtensionMember) {
+      int fileOffset = expression.fileOffset;
+      switch (readTarget.extensionMethodKind) {
+        case kernel.ProcedureKind.Getter:
+          expression.parent.replaceChild(
+              expression,
+              replacement = expression = helper.forest.createStaticInvocation(
+                  fileOffset,
+                  readTarget.member,
+                  helper.forest.createArgumentsForExtensionMethod(
+                      fileOffset,
+                      readTarget.inferredExtensionTypeArguments.length,
+                      0,
+                      receiver,
+                      extensionTypeArguments:
+                          readTarget.inferredExtensionTypeArguments)));
+          break;
+        case kernel.ProcedureKind.Method:
+          expression.parent.replaceChild(
+              expression,
+              replacement = expression = helper.forest.createStaticInvocation(
+                  fileOffset,
+                  readTarget.tearoffTarget,
+                  helper.forest.createArgumentsForExtensionMethod(
+                      fileOffset,
+                      readTarget.inferredExtensionTypeArguments.length,
+                      0,
+                      receiver,
+                      extensionTypeArguments:
+                          readTarget.inferredExtensionTypeArguments)));
+          break;
+        case kernel.ProcedureKind.Setter:
+        case kernel.ProcedureKind.Factory:
+        case kernel.ProcedureKind.Operator:
+          unhandled('$readTarget', "inferPropertyGet", fileOffset, uri);
+          break;
+      }
     }
     storeInferredType(expression, inferredType);
+    return new ExpressionInferenceResult(inferredType, replacement);
   }
 
   /// Modifies a type as appropriate when inferring a closure return type.
@@ -1759,35 +2292,38 @@
   MethodContravarianceCheckKind preCheckInvocationContravariance(
       Expression receiver,
       DartType receiverType,
-      Object interfaceMember,
+      ObjectAccessTarget target,
       MethodInvocation desugaredInvocation,
       Arguments arguments,
       Expression expression) {
-    if (interfaceMember is Field ||
-        interfaceMember is Procedure &&
-            interfaceMember.kind == ProcedureKind.Getter) {
-      DartType getType = getCalleeType(interfaceMember, receiverType);
-      if (getType is DynamicType) {
-        return MethodContravarianceCheckKind.none;
-      }
-      if (receiver != null && receiver is! ThisExpression) {
-        if ((interfaceMember is Field &&
-                returnedTypeParametersOccurNonCovariantly(
-                    interfaceMember.enclosingClass, interfaceMember.type)) ||
-            (interfaceMember is Procedure &&
-                returnedTypeParametersOccurNonCovariantly(
-                    interfaceMember.enclosingClass,
-                    interfaceMember.function.returnType))) {
-          return MethodContravarianceCheckKind.checkGetterReturn;
+    if (target.isInstanceMember) {
+      Member interfaceMember = target.member;
+      if (interfaceMember is Field ||
+          interfaceMember is Procedure &&
+              interfaceMember.kind == ProcedureKind.Getter) {
+        DartType getType = getGetterType(target, receiverType);
+        if (getType is DynamicType) {
+          return MethodContravarianceCheckKind.none;
         }
+        if (receiver != null && receiver is! ThisExpression) {
+          if ((interfaceMember is Field &&
+                  returnedTypeParametersOccurNonCovariantly(
+                      interfaceMember.enclosingClass, interfaceMember.type)) ||
+              (interfaceMember is Procedure &&
+                  returnedTypeParametersOccurNonCovariantly(
+                      interfaceMember.enclosingClass,
+                      interfaceMember.function.returnType))) {
+            return MethodContravarianceCheckKind.checkGetterReturn;
+          }
+        }
+      } else if (receiver != null &&
+          receiver is! ThisExpression &&
+          interfaceMember is Procedure &&
+          returnedTypeParametersOccurNonCovariantly(
+              interfaceMember.enclosingClass,
+              interfaceMember.function.returnType)) {
+        return MethodContravarianceCheckKind.checkMethodReturn;
       }
-    } else if (receiver != null &&
-        receiver is! ThisExpression &&
-        interfaceMember is Procedure &&
-        returnedTypeParametersOccurNonCovariantly(
-            interfaceMember.enclosingClass,
-            interfaceMember.function.returnType)) {
-      return MethodContravarianceCheckKind.checkMethodReturn;
     }
     return MethodContravarianceCheckKind.none;
   }
@@ -1862,7 +2398,7 @@
       Class class_, Name name, bool setter, int charOffset) {
     Member member = engine.hierarchyBuilder.getCombinedMemberSignatureKernel(
         class_, name, setter, charOffset, library);
-    if (member == null && (library?.isPatch ?? false)) {
+    if (member == null && library.isPatch) {
       // TODO(dmitryas): Hack for parts.
       member ??=
           classHierarchy.getInterfaceMember(class_, name, setter: setter);
@@ -2073,8 +2609,154 @@
 
 /// The result of an expression inference.
 class ExpressionInferenceResult {
-  final Expression expression;
-  final DartType type;
+  /// The inferred type of the expression.
+  final DartType inferredType;
 
-  ExpressionInferenceResult(this.expression, this.type);
+  /// If not-null, the [replacement] that replaced the inferred expression.
+  final Expression replacement;
+
+  const ExpressionInferenceResult(this.inferredType, [this.replacement]);
+}
+
+enum ObjectAccessTargetKind {
+  instanceMember,
+  callFunction,
+  unresolved,
+  extensionMember,
+}
+
+/// Result for performing an access on an object, like `o.foo`, `o.foo()` and
+/// `o.foo = ...`.
+class ObjectAccessTarget {
+  final ObjectAccessTargetKind kind;
+  final Member member;
+
+  const ObjectAccessTarget.internal(this.kind, this.member);
+
+  /// Creates an access to the instance [member].
+  factory ObjectAccessTarget.interfaceMember(Member member) {
+    assert(member != null);
+    return new ObjectAccessTarget.internal(
+        ObjectAccessTargetKind.instanceMember, member);
+  }
+
+  /// Creates an access to the extension [member].
+  factory ObjectAccessTarget.extensionMember(
+      Member member,
+      Member tearoffTarget,
+      ProcedureKind kind,
+      List<DartType> inferredTypeArguments) = ExtensionAccessTarget;
+
+  /// Creates an access to a 'call' method on a function, i.e. a function
+  /// invocation.
+  const ObjectAccessTarget.callFunction()
+      : this.internal(ObjectAccessTargetKind.callFunction, null);
+
+  /// Creates an access with no target.
+  ///
+  /// Done depending on context this may or may not be an error. For instance
+  /// if the receiver has type `dynamic` this is not an error.
+  const ObjectAccessTarget.unresolved()
+      : this.internal(ObjectAccessTargetKind.unresolved, null);
+
+  /// Returns `true` if this is an access to an instance member.
+  bool get isInstanceMember => kind == ObjectAccessTargetKind.instanceMember;
+
+  /// Returns `true` if this is an access to an extension member.
+  bool get isExtensionMember => kind == ObjectAccessTargetKind.extensionMember;
+
+  /// Returns `true` if this is an access to the 'call' method on a function.
+  bool get isCallFunction => kind == ObjectAccessTargetKind.callFunction;
+
+  /// Returns `true` if this is an access without a known target.
+  bool get isUnresolved => kind == ObjectAccessTargetKind.unresolved;
+
+  /// Returns the original procedure kind, if this is an extension method
+  /// target.
+  ///
+  /// This is need because getters, setters, and methods are converted into
+  /// top level methods, but access and invocation should still be treated as
+  /// if they are the original procedure kind.
+  ProcedureKind get extensionMethodKind =>
+      throw new UnsupportedError('ObjectAccessTarget.extensionMethodKind');
+
+  /// Returns inferred type arguments for the type parameters of an extension
+  /// method that comes from the extension declaration.
+  List<DartType> get inferredExtensionTypeArguments =>
+      throw new UnsupportedError(
+          'ObjectAccessTarget.inferredExtensionTypeArguments');
+
+  /// Returns the member to use for a tearoff.
+  ///
+  /// This is currently used for extension methods.
+  // TODO(johnniwinther): Normalize use by having `readTarget` and
+  //  `invokeTarget`?
+  Member get tearoffTarget =>
+      throw new UnsupportedError('ObjectAccessTarget.tearoffTarget');
+
+  @override
+  String toString() => 'ObjectAccessTarget($kind,$member)';
+}
+
+class ExtensionAccessTarget extends ObjectAccessTarget {
+  final Member tearoffTarget;
+  final ProcedureKind extensionMethodKind;
+  final List<DartType> inferredExtensionTypeArguments;
+
+  ExtensionAccessTarget(Member member, this.tearoffTarget,
+      this.extensionMethodKind, this.inferredExtensionTypeArguments)
+      : super.internal(ObjectAccessTargetKind.extensionMember, member);
+
+  @override
+  String toString() =>
+      'ExtensionAccessTarget($kind,$member,$extensionMethodKind)';
+}
+
+class ExtensionAccessCandidate {
+  final bool isPlatform;
+  final DartType onType;
+  final DartType onTypeInstantiateToBounds;
+  final ExtensionAccessTarget target;
+
+  ExtensionAccessCandidate(Extension extension, this.onType,
+      this.onTypeInstantiateToBounds, this.target)
+      : isPlatform = extension.enclosingLibrary.importUri.scheme == 'dart';
+
+  bool isMoreSpecificThan(TypeSchemaEnvironment typeSchemaEnvironment,
+      ExtensionAccessCandidate other) {
+    if (this.isPlatform == other.isPlatform) {
+      // Both are platform or not platform.
+      bool thisIsSubtype =
+          typeSchemaEnvironment.isSubtypeOf(this.onType, other.onType);
+      bool thisIsSupertype =
+          typeSchemaEnvironment.isSubtypeOf(other.onType, this.onType);
+      if (thisIsSubtype && !thisIsSupertype) {
+        // This is subtype of other and not vice-versa.
+        return true;
+      } else if (thisIsSupertype && !thisIsSubtype) {
+        // [other] is subtype of this and not vice-versa.
+        return false;
+      } else if (thisIsSubtype || thisIsSupertype) {
+        thisIsSubtype = typeSchemaEnvironment.isSubtypeOf(
+            this.onTypeInstantiateToBounds, other.onTypeInstantiateToBounds);
+        thisIsSupertype = typeSchemaEnvironment.isSubtypeOf(
+            other.onTypeInstantiateToBounds, this.onTypeInstantiateToBounds);
+        if (thisIsSubtype && !thisIsSupertype) {
+          // This is subtype of other and not vice-versa.
+          return true;
+        } else if (thisIsSupertype && !thisIsSubtype) {
+          // [other] is subtype of this and not vice-versa.
+          return false;
+        }
+      }
+    } else if (other.isPlatform) {
+      // This is not platform, [other] is: this  is more specific.
+      return true;
+    } else {
+      // This is platform, [other] is not: other is more specific.
+      return false;
+    }
+    // Neither is more specific than the other.
+    return null;
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
index e5ba185..1634efb 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
@@ -32,7 +32,7 @@
 }
 
 /// Extension of [Printer] that represents the unknown type as `?`.
-class TypeSchemaPrinter extends Printer implements TypeSchemaVisitor<Null> {
+class TypeSchemaPrinter extends Printer {
   TypeSchemaPrinter(StringSink sink,
       {NameSystem syntheticNames,
       bool showExternal,
@@ -47,17 +47,11 @@
             annotator: annotator);
 
   @override
-  visitUnknownType(UnknownType node) {
+  defaultDartType(covariant UnknownType node) {
     writeWord('?');
   }
 }
 
-/// Extension of [DartTypeVisitor] which can visit [UnknownType].
-class TypeSchemaVisitor<R> extends DartTypeVisitor<R> {
-  /// Called when [UnknownType] is visited.
-  R visitUnknownType(UnknownType node) => defaultDartType(node);
-}
-
 /// The unknown type (denoted `?`) is an object which can appear anywhere that
 /// a type is expected.  It represents a component of a type which has not yet
 /// been fixed by inference.
@@ -77,21 +71,12 @@
   }
 
   @override
-  accept(DartTypeVisitor<dynamic> v) {
-    if (v is TypeSchemaVisitor<dynamic>) {
-      return v.visitUnknownType(this);
-    } else {
-      // Note: in principle it seems like this should throw, since any visitor
-      // that operates on a type schema ought to inherit from TypeSchemaVisitor.
-      // However, that would make it impossible to use toString() on any type
-      // schema, since toString() uses the kernel's Printer visitor, which can't
-      // possibly inherit from TypeSchemaVisitor since it's inside kernel.
-      return v.defaultDartType(this);
-    }
+  R accept<R>(DartTypeVisitor<R> v) {
+    return v.defaultDartType(this);
   }
 
   @override
-  accept1(DartTypeVisitor1<dynamic, dynamic> v, arg) =>
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) =>
       v.defaultDartType(this, arg);
 
   @override
@@ -99,9 +84,9 @@
 }
 
 /// Visitor that computes [isKnown].
-class _IsKnownVisitor extends TypeSchemaVisitor<bool> {
+class _IsKnownVisitor extends DartTypeVisitor<bool> {
   @override
-  bool defaultDartType(DartType node) => true;
+  bool defaultDartType(DartType node) => node is! UnknownType;
 
   @override
   bool visitFunctionType(FunctionType node) {
@@ -130,7 +115,4 @@
     }
     return true;
   }
-
-  @override
-  bool visitUnknownType(UnknownType node) => false;
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index 5c0233d..1b8cd24 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -3,11 +3,17 @@
 // BSD-style license that can be found in the LICENSE.md file.
 
 import 'package:kernel/ast.dart'
-    show DartType, DynamicType, FunctionType, InterfaceType, NamedType;
+    show
+        DartType,
+        DartTypeVisitor,
+        DynamicType,
+        FunctionType,
+        InterfaceType,
+        NamedType;
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
-import 'type_schema.dart' show TypeSchemaVisitor, UnknownType;
+import 'type_schema.dart' show UnknownType;
 
 /// Returns the greatest closure of the given type [schema] with respect to `?`.
 ///
@@ -46,7 +52,7 @@
 /// Each visitor method returns `null` if there are no `?`s contained in the
 /// type, otherwise it returns the result of substituting `?` with `Null` or
 /// `Object`, as appropriate.
-class _TypeSchemaEliminationVisitor extends TypeSchemaVisitor<DartType> {
+class _TypeSchemaEliminationVisitor extends DartTypeVisitor<DartType> {
   final DartType nullType;
 
   bool isLeastClosure;
@@ -115,8 +121,12 @@
   }
 
   @override
-  DartType visitUnknownType(UnknownType node) =>
-      isLeastClosure ? nullType : const DynamicType();
+  DartType defaultDartType(DartType node) {
+    if (node is UnknownType) {
+      return isLeastClosure ? nullType : const DynamicType();
+    }
+    return null;
+  }
 
   /// Runs an instance of the visitor on the given [schema] and returns the
   /// resulting type.  If the schema contains no instances of `?`, the original
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index c6f7538..ec92375 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -33,14 +33,9 @@
 /// Test configuration used for testing CFE in its default state.
 const TestConfig defaultCfeConfig = const TestConfig(cfeMarker, 'cfe');
 
-/// Test configuration used for testing CFE with constant evaluation.
-const TestConfig cfeConstantUpdate2018Config = const TestConfig(
-    cfeMarker, 'cfe with constant-update-2018',
-    experimentalFlags: const {ExperimentalFlag.constantUpdate2018: true});
-
 /// Test configuration used for testing CFE with extension methods.
 const TestConfig cfeExtensionMethodsConfig = const TestConfig(
-    cfeMarker, 'cfe with constant-update-2018',
+    cfeMarker, 'cfe with extension methods',
     experimentalFlags: const {ExperimentalFlag.extensionMethods: true});
 
 class TestConfig {
@@ -49,6 +44,8 @@
   final Map<ExperimentalFlag, bool> experimentalFlags;
 
   const TestConfig(this.marker, this.name, {this.experimentalFlags = const {}});
+
+  void customizeCompilerOptions(CompilerOptions options) {}
 }
 
 // TODO(johnniwinther): Support annotations for compile-time errors.
@@ -245,6 +242,7 @@
   };
   options.debugDump = printCode;
   options.experimentalFlags.addAll(config.experimentalFlags);
+  config.customizeCompilerOptions(options);
   InternalCompilerResult compilerResult = await compileScript(
       testData.memorySourceFiles,
       options: options,
@@ -285,7 +283,9 @@
   }
 
   Map<Id, ActualData<T>> actualMapFor(TreeNode node) {
-    Uri uri = node is Library ? node.fileUri : node.location.file;
+    Uri uri = node is Library
+        ? node.fileUri
+        : (node is Member ? node.fileUri : node.location.file);
     return actualMaps.putIfAbsent(uri, () => <Id, ActualData<T>>{});
   }
 
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 83179c8..d32d8f5 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -97,7 +97,7 @@
   });
 }
 
-TypeParameterScopeBuilder lookupLibraryDeclarationBuilder(
+LibraryBuilder lookupLibraryBuilder(
     InternalCompilerResult compilerResult, Library library,
     {bool required: true}) {
   SourceLoader loader = compilerResult.kernelTargetForTesting.loader;
@@ -105,6 +105,14 @@
   if (builder == null && required) {
     throw new ArgumentError("DeclarationBuilder for $library not found.");
   }
+  return builder;
+}
+
+TypeParameterScopeBuilder lookupLibraryDeclarationBuilder(
+    InternalCompilerResult compilerResult, Library library,
+    {bool required: true}) {
+  SourceLibraryBuilder builder =
+      lookupLibraryBuilder(compilerResult, library, required: required);
   return builder.libraryDeclaration;
 }
 
@@ -196,8 +204,8 @@
   return memberBuilder;
 }
 
-/// Look up the [MemberBuilder] for [member] through the [ClassBuilder] for
-/// [cls] using [memberName] as its name.
+/// Look up the [MemberBuilder] for [member] through the [ExtensionBuilder] for
+/// [extension] using [memberName] as its name.
 MemberBuilder lookupExtensionMemberBuilder(
     InternalCompilerResult compilerResult,
     Extension extension,
@@ -254,7 +262,7 @@
     }
   }
 
-  void defaultConstant(Constant node) => throw UnimplementedError(
+  void defaultConstant(Constant node) => throw new UnimplementedError(
       'Unexpected constant $node (${node.runtimeType})');
 
   void visitNullConstant(NullConstant node) {
@@ -378,8 +386,8 @@
     }
   }
 
-  void defaultDartType(DartType node) =>
-      throw UnimplementedError('Unexpected type $node (${node.runtimeType})');
+  void defaultDartType(DartType node) => throw new UnimplementedError(
+      'Unexpected type $node (${node.runtimeType})');
 
   void visitInvalidType(InvalidType node) {
     sb.write('<invalid>');
@@ -525,25 +533,24 @@
   if (descriptor.isStatic) {
     sb.write('static ');
   }
-  if (descriptor.kind == null) {
-    sb.write('field ');
-  } else {
-    switch (descriptor.kind) {
-      case ProcedureKind.Method:
-        break;
-      case ProcedureKind.Getter:
-        sb.write('getter ');
-        break;
-      case ProcedureKind.Setter:
-        sb.write('setter ');
-        break;
-      case ProcedureKind.Operator:
-        sb.write('operator ');
-        break;
-      case ProcedureKind.Factory:
-        throw new UnsupportedError(
-            "Unexpected procedure kind ${descriptor.kind}.");
-    }
+  switch (descriptor.kind) {
+    case ExtensionMemberKind.Method:
+      break;
+    case ExtensionMemberKind.Getter:
+      sb.write('getter ');
+      break;
+    case ExtensionMemberKind.Setter:
+      sb.write('setter ');
+      break;
+    case ExtensionMemberKind.Operator:
+      sb.write('operator ');
+      break;
+    case ExtensionMemberKind.Field:
+      sb.write('field ');
+      break;
+    case ExtensionMemberKind.TearOff:
+      sb.write('tearoff ');
+      break;
   }
   sb.write(descriptor.name.name);
   sb.write('=');
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 56dfe2e..8d11e08 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -103,6 +103,8 @@
 ConstEvalNotListOrSetInSpread/example: Fail
 ConstEvalNotMapInSpread/example: Fail
 ConstEvalNullValue/example: Fail
+ConstEvalStartingPoint/analyzerCode: Fail # This is just used for displaying the starting point.
+ConstEvalStartingPoint/example: Fail # This is just used for displaying the starting point.
 ConstEvalUnevaluated/analyzerCode: Fail
 ConstEvalUnevaluated/example: Fail
 ConstEvalZeroDivisor/example: Fail
@@ -124,8 +126,6 @@
 CovariantMember/part_wrapped_script2: Fail
 CovariantMember/script1: Fail
 CovariantMember/script2: Fail
-CycleInTypeVariables/part_wrapped_script1: Fail
-CycleInTypeVariables/script1: Fail # We report an error for each type variable involved in the cycle.
 CyclicClassHierarchy/part_wrapped_script1: Fail
 CyclicClassHierarchy/part_wrapped_script2: Fail
 CyclicClassHierarchy/script1: Fail # We report an error for each class involved in the cycle.
@@ -193,6 +193,10 @@
 ExpectedUri/analyzerCode: Fail
 ExpectedUri/example: Fail
 ExperimentNotEnabled/example: Fail
+ExplicitExtensionArgumentMismatch/analyzerCode: Fail
+ExplicitExtensionArgumentMismatch/example: Fail
+ExplicitExtensionTypeArgumentMismatch/analyzerCode: Fail
+ExplicitExtensionTypeArgumentMismatch/example: Fail
 ExportAfterPart/part_wrapped_script1: Fail
 ExportAfterPart/script1: Fail
 ExpressionNotMetadata/analyzerCode: Fail
@@ -205,6 +209,9 @@
 ExternalFactoryRedirection/example: Fail
 ExternalFactoryWithBody/part_wrapped_script1: Fail
 ExternalFactoryWithBody/script1: Fail
+ExtensionDeclaresAbstractMember/example: Fail
+ExtensionDeclaresConstructor/example: Fail
+ExtensionDeclaresInstanceField/example: Fail
 ExtraneousModifier/part_wrapped_script1: Fail
 ExtraneousModifier/part_wrapped_script2: Fail
 ExtraneousModifier/part_wrapped_script3: Fail
@@ -258,6 +265,10 @@
 FfiExtendsOrImplementsSealedClass/analyzerCode: Fail
 FfiStructGeneric/analyzerCode: Fail
 FfiWrongStructInheritance/analyzerCode: Fail
+FfiExpectedExceptionalReturn/analyzerCode: Fail
+FfiExpectedNoExceptionalReturn/analyzerCode: Fail
+FfiExpectedConstant/analyzerCode: Fail
+FfiExceptionalReturnNull/analyzerCode: Fail
 FieldInitializedOutsideDeclaringClass/part_wrapped_script1: Fail
 FieldInitializedOutsideDeclaringClass/script1: Fail
 FieldInitializerOutsideConstructor/part_wrapped_script1: Fail
@@ -363,6 +374,7 @@
 MissingMain/example: Fail
 MissingPartOf/part_wrapped_script: Fail # Using 'part' in the (now) part.
 MissingPrefixInDeferredImport/example: Fail
+MixinDeclaresConstructor/example: Fail
 MixinInferenceNoMatchingClass/example: Fail
 ModifierOutOfOrder/part_wrapped_script1: Fail
 ModifierOutOfOrder/script1: Fail
@@ -407,6 +419,7 @@
 OverrideMoreRequiredArguments/example: Fail
 OverrideTypeMismatchParameter/example: Fail
 OverrideTypeMismatchReturnType/example: Fail
+OverrideTypeMismatchSetter/example: Fail
 OverrideTypeVariablesMismatch/example: Fail
 PackageNotFound/analyzerCode: Fail
 PackageNotFound/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 4ba9581..a1b889c 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -82,6 +82,9 @@
   analyzerCode: ILLEGAL_CHARACTER
   expression: "\x1b 1"
 
+ConstEvalStartingPoint:
+  template: "Constant evaluation error:"
+
 ConstEvalContext:
   template: "While analyzing:"
 
@@ -1858,13 +1861,38 @@
       }
 
 IllegalMixinDueToConstructors:
+  # a class with a constructor is used as a mixin
   template: "Can't use '#name' as a mixin because it has constructors."
-  analyzerCode: MIXIN_DECLARES_CONSTRUCTOR
+  analyzerCode: MIXIN_DECLARES_CONSTRUCTOR # CompileTimeErrorCode
+
+MixinDeclaresConstructor:
+  # a mixin declaration contains a constructor declaration
+  index: 95
+  template: "Mixins can't declare constructors."
+  analyzerCode: ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR
 
 IllegalMixinDueToConstructorsCause:
   template: "This constructor prevents using '#name' as a mixin."
   severity: CONTEXT
 
+ExtensionDeclaresAbstractMember:
+  index: 94
+  template: "Extensions can't declare abstract members."
+  tip: "Try providing an implementation for the member."
+  analyzerCode: ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER
+
+ExtensionDeclaresConstructor:
+  index: 92
+  template: "Extensions can't declare constructors."
+  tip: "Try removing the constructor declaration."
+  analyzerCode: ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR
+
+ExtensionDeclaresInstanceField:
+  index: 93
+  template: "Extensions can't declare instance fields"
+  tip: "Try removing the field declaration or making it a static field"
+  analyzerCode: ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD
+
 ConflictsWithConstructor:
   template: "Conflicts with constructor '#name'."
   analyzerCode: CONFLICTS_WITH_CONSTRUCTOR
@@ -2015,6 +2043,10 @@
   tip: "Change to a subtype of '#type2'."
   analyzerCode: INVALID_METHOD_OVERRIDE
 
+OverrideTypeMismatchSetter:
+  template: "The field '#name' has type '#type', which does not match the corresponding type, '#type2', in the overridden setter, '#name2'."
+  analyzerCode: INVALID_METHOD_OVERRIDE
+
 PartOfSelf:
   template: "A file can't be a part of itself."
   analyzerCode: PART_OF_NON_PART
@@ -3463,17 +3495,17 @@
 
 FfiFieldAnnotation:
   # Used by dart:ffi
-  template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
+  template: "Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
   external: test/ffi_test.dart
 
 FfiFieldNoAnnotation:
   # Used by dart:ffi
-  template: "Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++."
+  template: "Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code."
   external: test/ffi_test.dart
 
 FfiNotStatic:
   # Used by dart:ffi
-  template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c."
+  template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."
   external: test/ffi_test.dart
 
 FfiFieldInitializer:
@@ -3501,6 +3533,26 @@
   template: "Expected '#type' to be a subtype of '#type2'."
   external: test/ffi_test.dart
 
+FfiExpectedExceptionalReturn:
+  # Used by dart:ffi
+  template: "Expected an exceptional return value for a native callback returning '#type'."
+  external: test/ffi_test.dart
+
+FfiExpectedNoExceptionalReturn:
+  # Used by dart:ffi
+  template: "Exceptional return value cannot be provided for a native callback returning '#type'."
+  external: test/ffi_test.dart
+
+FfiExpectedConstant:
+  # Used by dart:ffi
+  template: "Exceptional return value must be a constant."
+  external: test/ffi_test.dart
+
+FfiExceptionalReturnNull:
+  # Used by dart:ffi
+  template: "Exceptional return value must not be null."
+  external: test/ffi_test.dart
+
 SpreadTypeMismatch:
   template: "Unexpected type '#type' of a spread.  Expected 'dynamic' or an Iterable."
   script:
@@ -3640,3 +3692,9 @@
       // @dart = 2.3
 
       part of 'main.dart';
+
+ExplicitExtensionArgumentMismatch:
+  template: "Explicit extension application requires exactly 1 positional argument."
+
+ExplicitExtensionTypeArgumentMismatch:
+  template: "Explicit extension application of extension '#name' takes '#count' type argument(s)."
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 876a203..ea3f3bf 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -1,24 +1,24 @@
 name: front_end
 # Currently, front_end API is not stable and users should not
 # depend on semver semantics when depending on this package.
-version: 0.1.23
+version: 0.1.24
 author: Dart Team <misc@dartlang.org>
 description: Front end for compilation of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
 environment:
   sdk: '>=2.2.2 <3.0.0'
 dependencies:
-  kernel: 0.3.23
+  kernel: 0.3.24
   package_config: '^1.1.0'
-  path: '^1.3.9'
-  yaml: '^2.1.12'
 dev_dependencies:
-  analyzer: 0.38.1
+  analyzer: 0.38.2
   args: '>=0.13.0 <2.0.0'
   build_integration:
     path: ../build_integration
   dart_style: '^1.0.7'
   json_rpc_2: ^2.0.9
+  path: '^1.3.9'
   test: ^1.3.4
   test_reflective_loader: ^0.1.0
   web_socket_channel: ^1.0.4
+  yaml: '^2.1.12'
diff --git a/pkg/front_end/test/binary_md_dill_reader.dart b/pkg/front_end/test/binary_md_dill_reader.dart
new file mode 100644
index 0000000..44e75c8
--- /dev/null
+++ b/pkg/front_end/test/binary_md_dill_reader.dart
@@ -0,0 +1,826 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:math" as math;
+
+class BinaryMdDillReader {
+  final String _binaryMdContent;
+
+  /// The actual binary content.
+  final List<int> _dillContent;
+
+  String _currentlyUnparsed = "";
+  Map<String, List<String>> _readingInstructions;
+  Map<String, List<String>> _generics;
+  Map<int, String> tagToName;
+  Map<int, String> constantTagToName;
+  int version;
+  Map<String, String> _extends;
+  int _binaryMdNestingDepth;
+  String _binaryMdCurrentClass;
+
+  /// The offset in the binary where we're supposed to read next.
+  int _binaryOffset;
+
+  int _depth;
+  Map _dillStringsPointer;
+  int verboseLevel = 0;
+  bool _ranSetup = false;
+
+  BinaryMdDillReader(this._binaryMdContent, this._dillContent);
+
+  void setup() {
+    if (!_ranSetup) {
+      _setupFields();
+      _readBinaryMd();
+      _ranSetup = true;
+    }
+  }
+
+  Map attemptRead() {
+    setup();
+    return _readDill();
+  }
+
+  /// Initialize the bare essentials, e.g. that a double is 8 bytes.
+  void _setupFields() {
+    _readingInstructions = {
+      "Byte": ["byte"],
+      "UInt32": ["byte", "byte", "byte", "byte"],
+      "Double": ["byte", "byte", "byte", "byte", "byte", "byte", "byte", "byte"]
+    };
+    _generics = {};
+    tagToName = {};
+    constantTagToName = {};
+    _extends = {};
+    _binaryMdNestingDepth = 0;
+    _binaryMdCurrentClass = "";
+  }
+
+  /// Read the binary.md text and put the data into the various tables.
+  void _readBinaryMd() {
+    List<String> lines = _binaryMdContent.split("\n");
+    bool inComment = false;
+    for (String s in lines) {
+      if (s.trim().startsWith("//") || s.trim() == "") {
+        continue;
+      } else if (s.trim().startsWith("/*")) {
+        inComment = true;
+        continue;
+      } else if (s.trim().startsWith("*/")) {
+        inComment = false;
+        continue;
+      } else if (inComment) {
+        continue;
+      } else if (s.trim().startsWith("type ") ||
+          s.trim().startsWith("abstract type ") ||
+          s.trim().startsWith("enum ")) {
+        _binaryMdHandlePossibleClassStart(s);
+      } else if (s.trim() == "if name begins with '_' {" &&
+          _binaryMdCurrentClass == "Name") {
+        // Special-case if sentence in Name.
+        _binaryMdNestingDepth++;
+      } else if (s.trim().endsWith("{")) {
+        throw "Unhandled case: $s";
+      } else if (s.trim() == "}") {
+        _binaryMdNestingDepth--;
+        _binaryMdCurrentClass = "";
+      } else if (_binaryMdNestingDepth > 0 && _binaryMdCurrentClass != "") {
+        _binaryMdHandleContent(s);
+      }
+    }
+
+    _binaryMdCheckHasAllTypes();
+    if (verboseLevel > 0) {
+      print("Seems to find all types.");
+    }
+  }
+
+  int numLibs;
+  int binaryOffsetForSourceTable;
+  int binaryOffsetForCanonicalNames;
+  int binaryOffsetForMetadataPayloads;
+  int binaryOffsetForMetadataMappings;
+  int binaryOffsetForStringTable;
+  int binaryOffsetForConstantTable;
+  int mainMethodReference;
+
+  /// Read the dill file data, parsing it into a Map.
+  Map _readDill() {
+    _binaryOffset = 0;
+    _depth = 0;
+
+    // Hack start: Read ComponentIndex first.
+    _binaryOffset = _dillContent.length - (4 * 2);
+    numLibs = _peekUint32();
+
+    // Skip to the start of the index.
+    _binaryOffset = _dillContent.length -
+        ((numLibs + 1) + 9 /* number of fixed fields */) * 4;
+
+    // Read index.
+    binaryOffsetForSourceTable = _peekUint32();
+    _binaryOffset += 4;
+    binaryOffsetForCanonicalNames = _peekUint32();
+    _binaryOffset += 4;
+    binaryOffsetForMetadataPayloads = _peekUint32();
+    _binaryOffset += 4;
+    binaryOffsetForMetadataMappings = _peekUint32();
+    _binaryOffset += 4;
+    binaryOffsetForStringTable = _peekUint32();
+    _binaryOffset += 4;
+    binaryOffsetForConstantTable = _peekUint32();
+    _binaryOffset += 4;
+    mainMethodReference = _peekUint32();
+
+    _binaryOffset = binaryOffsetForStringTable;
+    var saved = _readingInstructions["ComponentFile"];
+    _readingInstructions["ComponentFile"] = ["StringTable strings;"];
+    _readBinary("ComponentFile");
+    _readingInstructions["ComponentFile"] = saved;
+    _binaryOffset = 0;
+    _depth = 0;
+    // Hack end.
+
+    Map componentFile = _readBinary("ComponentFile");
+    if (_binaryOffset != _dillContent.length) {
+      throw "Didn't read the entire binary: "
+          "Only read $_binaryOffset of ${_dillContent.length} bytes. "
+          "($componentFile)";
+    }
+    if (verboseLevel > 0) {
+      print("Successfully read the dill file.");
+    }
+    return componentFile;
+  }
+
+  /// Initial setup of a "class definition" in the binary.md file.
+  /// This includes parsing the name, setting up any "extends"-relationship,
+  /// generics etc.
+  _binaryMdHandlePossibleClassStart(String s) {
+    if (s.startsWith("type Byte =")) return;
+    if (s.startsWith("type UInt32 =")) return;
+
+    if (_binaryMdNestingDepth != 0 || _binaryMdCurrentClass != "") {
+      throw "Cannot handle nesting: "
+          "'$s', $_binaryMdNestingDepth, $_binaryMdCurrentClass";
+    }
+
+    if (s.contains("{")) _binaryMdNestingDepth++;
+    if (s.contains("}")) _binaryMdNestingDepth--;
+
+    String name = s.trim();
+    if (name.startsWith("abstract ")) name = name.substring("abstract ".length);
+    if (name.startsWith("type ")) name = name.substring("type ".length);
+    bool isEnum = false;
+    if (name.startsWith("enum ")) {
+      name = name.substring("enum ".length);
+      isEnum = true;
+    }
+    String nameExtends = null;
+    Match extendsMatch = (new RegExp("extends (.+)[ \{]")).firstMatch(name);
+    if (extendsMatch != null) {
+      nameExtends = extendsMatch.group(1);
+    }
+    name = _getType(name);
+    if (name.contains("<")) {
+      List<String> types = _getGenerics(name);
+      name = name.substring(0, name.indexOf("<")) + "<${types.length}>";
+      _generics[name] ??= types;
+    }
+    if (_binaryMdNestingDepth != 0) _binaryMdCurrentClass = name;
+    if (nameExtends != null) {
+      _extends[name] = nameExtends.trim();
+    }
+
+    if (isEnum) {
+      _readingInstructions[name] ??= ["byte"];
+    } else {
+      _readingInstructions[name] ??= [];
+    }
+  }
+
+  Map<String, String> _typeCache = {};
+
+  /// Extract the type/name of an input string, e.g. turns
+  ///
+  /// * "ClassLevel { Type = 0, [...], }" into "ClassLevel"
+  /// * "Class extends Node {" into "Class"
+  /// * "Byte tag = 97;" into "Byte"
+  /// * "List<T> {" into "List<T>"
+  String _getType(final String inputString) {
+    String cached = _typeCache[inputString];
+    if (cached != null) return cached;
+    int end = math.max(
+        math.max(inputString.indexOf(" "), inputString.lastIndexOf(">") + 1),
+        inputString.lastIndexOf("]") + 1);
+    if (end <= 0) end = inputString.length;
+    String result = inputString.substring(0, end);
+    if (result.contains(" extends")) {
+      result = result.substring(0, result.indexOf(" extends "));
+    }
+    _typeCache[inputString] = result;
+
+    return result;
+  }
+
+  /// Extract the generics used in an input type, e.g. turns
+  ///
+  /// * "Pair<A, B>" into ["A", "B"]
+  /// * "List<Expression>" into ["Expression"]
+  ///
+  /// Note that the input string *has* to use generics, i.e. have '<' and '>'
+  /// in it.
+  /// Also note that nested generics isn't really supported
+  /// (e.g. Foo<Bar<Baz>>).
+  List<String> _getGenerics(String s) {
+    s = s.substring(s.indexOf("<") + 1, s.lastIndexOf(">"));
+    if (s.contains("<")) {
+      if (s == "Pair<FileOffset, Expression>") {
+        return ["Pair<FileOffset, Expression>"];
+      } else if (s == "Pair<UInt32, UInt32>") {
+        return ["Pair<UInt32, UInt32>"];
+      } else if (s == "Pair<FieldReference, Expression>") {
+        return ["Pair<FieldReference, Expression>"];
+      } else if (s == "Pair<ConstantReference, ConstantReference>") {
+        return ["Pair<ConstantReference, ConstantReference>"];
+      } else if (s == "Pair<FieldReference, ConstantReference>") {
+        return ["Pair<FieldReference, ConstantReference>"];
+      }
+      throw "Doesn't supported nested generics (input: $s).";
+    }
+
+    return s.split(",").map((untrimmed) => untrimmed.trim()).toList();
+  }
+
+  /// Parses a line of binary.md content for a "current class" into the
+  /// reading-instructions for that class.
+  /// There is special handling around tags, and around lines that are split,
+  /// i.e. not yet finished (not ending in a semi-colon).
+  void _binaryMdHandleContent(String s) {
+    if (s.trim().startsWith("UInt32 formatVersion = ")) {
+      String versionString =
+          s.trim().substring("UInt32 formatVersion = ".length);
+      if (versionString.endsWith(";")) {
+        versionString = versionString.substring(0, versionString.length - 1);
+      }
+      if (version != null) {
+        throw "Already have a version set ($version), "
+            "now trying to set $versionString";
+      }
+      version = int.parse(versionString);
+    }
+    if (s.trim().startsWith("Byte tag = ")) {
+      String tag = s.trim().substring("Byte tag = ".length);
+      if (tag.endsWith(";")) tag = tag.substring(0, tag.length - 1);
+      if (tag == "128 + N; // Where 0 <= N < 8.") {
+        for (int n = 0; n < 8; ++n) {
+          tagToName[128 + n] = _binaryMdCurrentClass;
+        }
+      } else if (tag == "136 + N; // Where 0 <= N < 8.") {
+        for (int n = 0; n < 8; ++n) {
+          tagToName[136 + n] = _binaryMdCurrentClass;
+        }
+      } else if (tag == "144 + N; // Where 0 <= N < 8.") {
+        for (int n = 0; n < 8; ++n) {
+          tagToName[144 + n] = _binaryMdCurrentClass;
+        }
+      } else {
+        if (tag.contains("; // Note: tag is out of order")) {
+          tag = tag.substring(0, tag.indexOf("; // Note: tag is out of order"));
+        }
+        Map<int, String> tagMap;
+        if (_isA(_binaryMdCurrentClass, "Constant")) {
+          tagMap = constantTagToName;
+        } else {
+          tagMap = tagToName;
+        }
+        if (tagMap[int.parse(tag)] != null) {
+          throw "Two tags with same name!: "
+              "$tag (${tagMap[int.parse(tag)]} and ${_binaryMdCurrentClass})";
+        }
+        tagMap[int.parse(tag)] = _binaryMdCurrentClass;
+      }
+    }
+
+    {
+      var line = _currentlyUnparsed + s.trim();
+      if (line.contains("//")) line = line.substring(0, line.indexOf("//"));
+      if (!line.trim().endsWith(";")) {
+        _currentlyUnparsed = line;
+        return;
+      }
+      s = line;
+      _currentlyUnparsed = "";
+    }
+
+    _readingInstructions[_binaryMdCurrentClass].add(s.trim());
+  }
+
+  /// Check the all types referenced by reading instructions are types we know
+  /// about.
+  void _binaryMdCheckHasAllTypes() {
+    for (String key in _readingInstructions.keys) {
+      for (String s in _readingInstructions[key]) {
+        String type = _getType(s);
+        if (!_isKnownType(type, key)) {
+          throw "Unknown type: $type (used in $key)";
+        }
+      }
+    }
+  }
+
+  /// Check that we know about the specific type, i.e. know something about how
+  /// to read it.
+  bool _isKnownType(String type, String parent) {
+    if (type == "byte") return true;
+    if (_readingInstructions[type] != null) return true;
+    if (type.contains("[") &&
+        _readingInstructions[type.substring(0, type.indexOf("["))] != null) {
+      return true;
+    }
+
+    if (parent.contains("<")) {
+      Set<String> types = _generics[parent].toSet();
+      if (types.contains(type)) return true;
+      if (type.contains("[") &&
+          types.contains(type.substring(0, type.indexOf("[")))) return true;
+    }
+    if (type.contains("<")) {
+      List<String> types = _getGenerics(type);
+      String renamedType =
+          type.substring(0, type.indexOf("<")) + "<${types.length}>";
+      if (_readingInstructions[renamedType] != null) {
+        bool ok = true;
+        for (String type in types) {
+          if (!_isKnownType(type, renamedType)) {
+            ok = false;
+            break;
+          }
+        }
+        if (ok) return true;
+      }
+    }
+
+    return false;
+  }
+
+  /// Get a string from the string table after the string table has been read
+  /// from the dill file.
+  String getDillString(int num) {
+    List<int> endOffsets =
+        (_dillStringsPointer["endOffsets"]["items"] as List<dynamic>).cast();
+    List<int> utf8 = (_dillStringsPointer["utf8Bytes"] as List<dynamic>).cast();
+    return new String.fromCharCodes(
+        utf8.sublist(num == 0 ? 0 : endOffsets[num - 1], endOffsets[num]));
+  }
+
+  RegExp regExpSplit = new RegExp(r"[\. ]");
+
+  /// Actually read the binary dill file. Read type [what] at the current
+  /// binary position as specified by field [_binaryOffset].
+  dynamic _readBinary(String what) {
+    ++_depth;
+    what = _remapWhat(what);
+
+    // Read any 'base types'.
+    if (what == "UInt") {
+      return _readUint();
+    }
+    if (what == "UInt32") {
+      return _readUint32();
+    }
+    if (what == "byte" || what == "Byte") {
+      int value = _dillContent[_binaryOffset];
+      ++_binaryOffset;
+      --_depth;
+      return value;
+    }
+
+    // Not a 'base type'. Read according to [_readingInstructions] field.
+    List<String> types = [];
+    List<String> typeNames = [];
+    String orgWhat = what;
+    int orgPosition = _binaryOffset;
+    if (what.contains("<")) {
+      types = _getGenerics(what);
+      what = what.substring(0, what.indexOf("<")) + "<${types.length}>";
+      typeNames = _generics[what];
+    }
+
+    if (_readingInstructions[what] == null) {
+      throw "Didn't find instructions for '$what'";
+    }
+
+    Map<String, dynamic> vars = {};
+    if (verboseLevel > 1) {
+      print("".padLeft(_depth * 2) + " -> $what ($orgWhat @ $orgPosition)");
+    }
+
+    for (String instruction in _readingInstructions[what]) {
+      // Special-case a few things that aren't (easily) described in the
+      // binary.md file.
+      if (what == "Name" && instruction == "LibraryReference library;") {
+        // Special-case if sentence in Name.
+        String name = getDillString(vars["name"]["index"]);
+        if (!name.startsWith("_")) continue;
+      } else if (what == "ComponentFile" &&
+          instruction == "MetadataPayload[] metadataPayloads;") {
+        // Special-case skipping metadata payloads.
+        _binaryOffset = binaryOffsetForMetadataMappings;
+        continue;
+      } else if (what == "ComponentFile" &&
+          instruction == "RList<MetadataMapping> metadataMappings;") {
+        // Special-case skipping metadata mappings.
+        _binaryOffset = binaryOffsetForStringTable;
+        continue;
+      } else if (what == "ComponentIndex" &&
+          instruction == "Byte[] 8bitAlignment;") {
+        // Special-case 8-byte alignment.
+        int sizeWithoutPadding = _binaryOffset +
+            ((numLibs + 1) + 9 /* number of fixed fields */) * 4;
+        int padding = 8 - sizeWithoutPadding % 8;
+        if (padding == 8) padding = 0;
+        _binaryOffset += padding;
+        continue;
+      }
+
+      String type = _getType(instruction);
+      String name = instruction.substring(type.length).trim();
+      if (name.contains("//")) {
+        name = name.substring(0, name.indexOf("//")).trim();
+      }
+      if (name.contains("=")) {
+        name = name.substring(0, name.indexOf("=")).trim();
+      }
+      if (name.endsWith(";")) name = name.substring(0, name.length - 1);
+      int oldOffset = _binaryOffset;
+
+      if (verboseLevel > 1) {
+        print("".padLeft(_depth * 2 + 1) +
+            " -> $instruction ($type) (@ $_binaryOffset) "
+                "($orgWhat @ $orgPosition)");
+      }
+
+      bool readNothingIsOk = false;
+      if (type.contains("[")) {
+        // The type is an array. Read into a List.
+        // Note that we need to know the length of that list.
+        String count = type.substring(type.indexOf("[") + 1, type.indexOf("]"));
+        type = type.substring(0, type.indexOf("["));
+        type = _lookupGenericType(typeNames, type, types);
+
+        int intCount = -1;
+        if (vars[count] != null && vars[count] is int) {
+          intCount = vars[count];
+        } else if (count.contains(".")) {
+          List<String> countData =
+              count.split(regExpSplit).map((s) => s.trim()).toList();
+          if (vars[countData[0]] != null) {
+            dynamic v = vars[countData[0]];
+            if (v is Map &&
+                countData[1] == "last" &&
+                v["items"] is List &&
+                v["items"].last is int) {
+              intCount = v["items"].last;
+            } else if (v is Map && v[countData[1]] != null) {
+              v = v[countData[1]];
+              if (v is Map && v[countData[2]] != null) {
+                v = v[countData[2]];
+                if (v is int) intCount = v;
+              } else if (v is int &&
+                  countData.length == 4 &&
+                  countData[2] == "+") {
+                intCount = v + int.parse(countData[3]);
+              }
+            } else {
+              throw "Unknown dot to int ($count)";
+            }
+          }
+        }
+
+        // Special-case that we know how many libraries we have.
+        if (intCount < 0 && type == "Library" && _depth == 1) {
+          intCount = numLibs;
+        }
+        if (intCount < 0 &&
+            type == "UInt32" &&
+            _depth == 2 &&
+            count == "libraryCount + 1") {
+          intCount = numLibs + 1;
+        }
+
+        if (intCount >= 0) {
+          readNothingIsOk = intCount == 0;
+          List<dynamic> value = new List(intCount);
+          for (int i = 0; i < intCount; ++i) {
+            int oldOffset2 = _binaryOffset;
+            value[i] = _readBinary(type);
+            if (_binaryOffset <= oldOffset2) {
+              throw "Didn't read anything for $type @ $_binaryOffset";
+            }
+          }
+          vars[name] = value;
+        } else {
+          throw "Array of unknown size ($count)";
+        }
+      } else {
+        // Not an array, read the single field recursively.
+        type = _lookupGenericType(typeNames, type, types);
+        dynamic value = _readBinary(type);
+        vars[name] = value;
+        _checkTag(instruction, value);
+      }
+      if (_binaryOffset <= oldOffset && !readNothingIsOk) {
+        throw "Didn't read anything for $type @ $_binaryOffset";
+      }
+
+      // Special case that when we read the string table we need to remember it
+      // to be able to lookup strings to read names properly later
+      // (private names has a library, public names does not).
+      if (what == "ComponentFile") {
+        if (name == "strings") _dillStringsPointer = vars[name];
+      }
+    }
+
+    --_depth;
+    return vars;
+  }
+
+  /// Verify, that if the instruction was a tag with a value
+  /// (e.g. "Byte tag = 5;"), then the value read was indeed the expected value
+  /// (5 in this example).
+  void _checkTag(String instruction, dynamic value) {
+    if (instruction.trim().startsWith("Byte tag = ")) {
+      String tag = instruction.trim().substring("Byte tag = ".length);
+      if (tag.contains("//")) {
+        tag = tag.substring(0, tag.indexOf("//")).trim();
+      }
+      if (tag.endsWith(";")) tag = tag.substring(0, tag.length - 1).trim();
+      int tagAsInt = int.tryParse(tag) ?? -1;
+      if (tagAsInt >= 0) {
+        if (tagAsInt != value) {
+          throw "Unexpected tag. "
+              "Expected $tagAsInt but got $value (around $_binaryOffset).";
+        }
+      }
+    }
+  }
+
+  /// Looks up any generics used, replacing the generic-name (if any) with the
+  /// actual type, e.g.
+  /// * ([], "UInt", []) into "UInt"
+  /// * (["T"], "T", ["Expression"]) into "Expression"
+  /// * (["T0", "T1"], "T0", ["FileOffset", "Expression"]) into "FileOffset"
+  String _lookupGenericType(
+      List<String> typeNames, String type, List<String> types) {
+    for (int i = 0; i < typeNames.length; ++i) {
+      if (typeNames[i] == type) {
+        type = types[i];
+        break;
+      }
+    }
+    return type;
+  }
+
+  /// Check if [what] is an [a], i.e. if [what] extends [a].
+  /// This method uses the [_extends] map and it is thus risky to use it before
+  /// the binary.md file has been read in entirety (because the field isn't
+  /// completely filled out yet).
+  bool _isA(String what, String a) {
+    String parent = what;
+    while (parent != null) {
+      if (parent == a) return true;
+      parent = _extends[parent];
+    }
+    return false;
+  }
+
+  /// Remaps the type by looking at tags, e.g. if asked to read an "Expression"
+  /// and the tag actually says "Block", return "Block" after checking that a
+  /// "Block" is actually an "Expression".
+  String _remapWhat(String what) {
+    Map<int, String> tagMap;
+    if (_isA(what, "Constant")) {
+      tagMap = constantTagToName;
+    } else {
+      tagMap = tagToName;
+    }
+
+    if (what == "Expression") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "Expression")) {
+          throw "Expected Expression but found $what";
+        }
+      } else {
+        throw "Unknown expression";
+      }
+    }
+    if (what == "IntegerLiteral") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "IntegerLiteral")) {
+          throw "Expected IntegerLiteral but found $what";
+        }
+      } else {
+        throw "Unknown IntegerLiteral";
+      }
+    }
+    if (what == "Statement") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "Statement")) {
+          throw "Expected Statement but found $what";
+        }
+      } else {
+        throw "Unknown Statement";
+      }
+    }
+    if (what == "Initializer") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "Initializer")) {
+          throw "Expected Initializer but found $what";
+        }
+      } else {
+        throw "Unknown Initializer";
+      }
+    }
+    if (what == "DartType") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "DartType")) {
+          throw "Expected DartType but found $what";
+        }
+      } else {
+        throw "Unknown DartType at $_binaryOffset "
+            "(${_dillContent[_binaryOffset]})";
+      }
+    }
+    if (what.startsWith("Option<")) {
+      if (tagMap[_dillContent[_binaryOffset]] != null &&
+          tagMap[_dillContent[_binaryOffset]].startsWith("Something<")) {
+        what = what.replaceFirst("Option<", "Something<");
+      }
+    }
+    if (what == "Constant") {
+      if (tagMap[_dillContent[_binaryOffset]] != null) {
+        what = tagMap[_dillContent[_binaryOffset]];
+        if (!_isA(what, "Constant")) {
+          throw "Expected Constant but found $what";
+        }
+      } else {
+        throw "Unknown Constant";
+      }
+    }
+
+    return what;
+  }
+
+  /// Read the "UInt" type as used in kernel. This is hard-coded.
+  /// Note that this decrements the [_depth] and increments the
+  /// [_binaryOffset] correctly.
+  int _readUint() {
+    int b = _dillContent[_binaryOffset];
+    if (b & 128 == 0) {
+      ++_binaryOffset;
+      --_depth;
+      return b;
+    }
+    if (b & 192 == 128) {
+      int value = (_dillContent[_binaryOffset] & 63) << 8 |
+          _dillContent[_binaryOffset + 1];
+      _binaryOffset += 2;
+      --_depth;
+      return value;
+    }
+    if (b & 192 == 192) {
+      int value = (_dillContent[_binaryOffset] & 63) << 24 |
+          _dillContent[_binaryOffset + 1] << 16 |
+          _dillContent[_binaryOffset + 2] << 8 |
+          _dillContent[_binaryOffset + 3];
+      _binaryOffset += 4;
+      --_depth;
+      return value;
+    }
+    throw "Unexpected UInt";
+  }
+
+  /// Read the "UInt43" type as used in kernel. This is hard-coded.
+  /// Note that this decrements the [_depth] and increments the
+  /// [_binaryOffset] correctly.
+  int _readUint32() {
+    int value = (_dillContent[_binaryOffset] & 63) << 24 |
+        _dillContent[_binaryOffset + 1] << 16 |
+        _dillContent[_binaryOffset + 2] << 8 |
+        _dillContent[_binaryOffset + 3];
+    _binaryOffset += 4;
+    --_depth;
+    return value;
+  }
+
+  /// Read the "UInt32" type as used in kernel. This is hard-coded.
+  /// This does not change any state.
+  int _peekUint32() {
+    return (_dillContent[_binaryOffset] & 63) << 24 |
+        _dillContent[_binaryOffset + 1] << 16 |
+        _dillContent[_binaryOffset + 2] << 8 |
+        _dillContent[_binaryOffset + 3];
+  }
+}
+
+class DillComparer {
+  Map<int, String> tagToName;
+  StringBuffer outputTo;
+
+  bool compare(List<int> a, List<int> b, String binaryMd,
+      [StringBuffer outputTo]) {
+    this.outputTo = outputTo;
+    bool printOnExit = false;
+    if (this.outputTo == null) {
+      this.outputTo = new StringBuffer();
+      printOnExit = true;
+    }
+    BinaryMdDillReader readerA = new BinaryMdDillReader(binaryMd, a);
+    dynamic aResult = readerA.attemptRead();
+    tagToName = readerA.tagToName;
+
+    BinaryMdDillReader readerB = new BinaryMdDillReader(binaryMd, b);
+    dynamic bResult = readerB.attemptRead();
+
+    bool result = _compareInternal(aResult, bResult);
+    if (printOnExit) print(outputTo);
+    return result;
+  }
+
+  bool _compareInternal(dynamic a, dynamic b) {
+    if (a.runtimeType != b.runtimeType) {
+      outputTo.writeln(
+          "Different runtime types (${a.runtimeType} and ${b.runtimeType})");
+      return false;
+    }
+    if (a is List) {
+      List listA = a;
+      List listB = b;
+      if (listA.length != listB.length) {
+        outputTo.writeln(
+            "Lists have different length (${listA.length} vs ${listB.length} "
+            "${_getTag(a)}");
+        return false;
+      }
+      for (int i = 0; i < listA.length; i++) {
+        if (!_compareInternal(listA[i], listB[i])) {
+          outputTo
+              .writeln("Lists have different values at index $i ${_getTag(a)}");
+          return false;
+        }
+      }
+      return true;
+    }
+
+    if (a is Map<String, dynamic>) {
+      Map<String, dynamic> mapA = a;
+      Map<String, dynamic> mapB = b;
+      for (String key in mapA.keys) {
+        dynamic valueA = mapA[key];
+        dynamic valueB = mapB[key];
+        if (!_compareInternal(valueA, valueB)) {
+          outputTo.writeln(
+              "Map with key '$key' has different values ${_getTag(a)}");
+          return false;
+        }
+      }
+      if (mapA.length != mapB.length) {
+        outputTo.writeln("Maps have different number of entries "
+            "(${mapA.length} vs ${mapB.length}). ${_getTag(a)}");
+        return false;
+      }
+      return true;
+    }
+
+    if (a is int) {
+      if (a != b) {
+        outputTo.writeln("Integers differ: $a vs $b");
+        return false;
+      }
+      return true;
+    }
+
+    throw "Unsupported: ${a.runtimeType}";
+  }
+
+  String _getTag(dynamic input) {
+    if (input is Map) {
+      dynamic tag = input["tag"];
+      if (tag != null) {
+        if (tagToName[tag] != null) {
+          return "(tag $tag, likely '${tagToName[tag]}')";
+        }
+        return "(tag $tag)";
+      }
+    }
+    return "";
+  }
+}
diff --git a/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart b/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart
new file mode 100644
index 0000000..5f30b25
--- /dev/null
+++ b/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart
@@ -0,0 +1,204 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show File, Platform;
+
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+    show DiagnosticMessage;
+
+import 'package:front_end/src/fasta/severity.dart' show Severity;
+
+import 'package:kernel/kernel.dart'
+    show Class, Component, ConstantExpression, Field, IntConstant, Library;
+
+import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
+
+import 'binary_md_dill_reader.dart' show BinaryMdDillReader;
+
+import 'incremental_load_from_dill_test.dart'
+    show getOptions, normalCompileToComponent;
+
+import 'utils/io_utils.dart' show computeRepoDir;
+
+const String maxSupported =
+    "static const uint32_t kMaxSupportedKernelFormatVersion = ";
+
+// Match stuff like "V(Nothing, 0)"
+final RegExp tagParser = new RegExp(r"V\((\w*),\s*(\d+)\)");
+
+// Match stuff like "kNullConstant = 0,"
+final RegExp constantTagParser = new RegExp(r"k(\w*)\s*=\s*(\d+)");
+
+main() async {
+  File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+  String binaryMdContent = binaryMd.readAsStringSync();
+
+  BinaryMdDillReader binaryMdReader =
+      new BinaryMdDillReader(binaryMdContent, []);
+  binaryMdReader.setup();
+
+  File vmTagFile = new File("$repoDir/runtime/vm/kernel_binary.h");
+  String vmTagContent = vmTagFile.readAsStringSync();
+  List<String> vmTagLines = vmTagContent.split("\n");
+  int vmVersion;
+  Map<int, String> vmTagToName = {};
+  Map<int, String> vmConstantTagToName = {};
+  for (int i = 0; i < vmTagLines.length; i++) {
+    String line = vmTagLines[i];
+    if (line.startsWith(maxSupported)) {
+      vmVersion = int.parse(line
+          .substring(line.indexOf(maxSupported) + maxSupported.length)
+          .substring(0, 2) // Assume version < 100 for now.
+          .trim());
+    } else if (line.startsWith("#define KERNEL_TAG_LIST(V)")) {
+      while (true) {
+        RegExpMatch match = tagParser.firstMatch(line);
+        if (match != null) {
+          int value = int.parse(match.group(2));
+          int end = value + 1;
+          if (uses8Tags(match.group(1))) {
+            end = value + 8;
+          }
+          for (int j = value; j < end; j++) {
+            vmTagToName[j] = match.group(1);
+          }
+        }
+        if (!vmTagLines[i].trim().endsWith(r"\")) {
+          break;
+        }
+        i++;
+        line = vmTagLines[i];
+      }
+    } else if (line.startsWith("enum ConstantTag {")) {
+      while (true) {
+        RegExpMatch match = constantTagParser.firstMatch(line);
+        if (match != null) {
+          vmConstantTagToName[int.parse(match.group(2))] = match.group(1);
+        }
+        if (vmTagLines[i].trim().startsWith("}")) {
+          break;
+        }
+        i++;
+        line = vmTagLines[i];
+      }
+    }
+  }
+
+  final Uri kernelTagUri = Uri.base.resolve("pkg/kernel/lib/binary/tag.dart");
+  Component c = await normalCompileToComponent(kernelTagUri,
+      options: getOptions()
+        ..target = new NoneTarget(new TargetFlags())
+        ..onDiagnostic = (DiagnosticMessage message) {
+          if (message.severity == Severity.error) {
+            print(message.plainTextFormatted.join('\n'));
+          }
+        });
+
+  Library tagLibrary =
+      c.libraries.firstWhere((l) => l.fileUri.pathSegments.last == "tag.dart");
+  Class tagClass = tagLibrary.classes.firstWhere((c) => c.name == "Tag");
+  Class constantTagClass =
+      tagLibrary.classes.firstWhere((c) => c.name == "ConstantTag");
+
+  int tagVersion;
+  for (TagCompare compareMe in [
+    new TagCompare(binaryMdReader.tagToName, binaryMdReader.version,
+        vmTagToName, vmVersion, tagClass),
+    new TagCompare(binaryMdReader.constantTagToName, binaryMdReader.version,
+        vmConstantTagToName, vmVersion, constantTagClass)
+  ]) {
+    Map<int, String> tagToName = {};
+    for (Field f in compareMe.tagClass.fields) {
+      // Class doesn't only contain tag stuff.
+      if (f.name.name.endsWith("Mask")) continue;
+      if (f.name.name.endsWith("HighBit")) continue;
+      if (f.name.name.endsWith("Bias")) continue;
+      if (f.name.name == "ComponentFile") continue;
+      ConstantExpression value = f.initializer;
+      IntConstant intConstant = value.constant;
+      int intValue = intConstant.value;
+      if (f.name.name == "BinaryFormatVersion") {
+        tagVersion = intValue;
+        continue;
+      }
+
+      int end = intValue + 1;
+      // There are a few special cases that takes up a total of 8 tags.
+      if (uses8Tags(f.name.name)) {
+        end = intValue + 8;
+      }
+      for (; intValue < end; intValue++) {
+        if (tagToName[intValue] != null) {
+          throw "Double entry for ${intValue}: "
+              "${f.name.name} and ${tagToName[intValue]}";
+        }
+        tagToName[intValue] = f.name.name;
+      }
+    }
+
+    Map<int, String> tagToNameMd = {};
+    for (MapEntry<int, String> entry in compareMe.mdTagToName.entries) {
+      if (entry.value.contains("<")) {
+        tagToNameMd[entry.key] =
+            entry.value.substring(0, entry.value.indexOf("<")).trim();
+      } else {
+        tagToNameMd[entry.key] = entry.value;
+      }
+    }
+
+    // Kernels tag.dart vs binary.mds tags.
+    for (int key in tagToNameMd.keys) {
+      String nameMd = tagToNameMd[key];
+      String name = tagToName[key];
+      if (nameMd == name) continue;
+      throw "$key: $nameMd vs $name";
+    }
+    for (int key in tagToName.keys) {
+      String nameMd = tagToNameMd[key];
+      String name = tagToName[key];
+      if (nameMd == name) continue;
+      throw "$key: $nameMd vs $name";
+    }
+    if (tagVersion != compareMe.mdVersion) {
+      throw "Version in tag.dart: $tagVersion; "
+          "version in binary.md: ${compareMe.mdVersion}";
+    }
+
+    // Kernels tag.dart vs the VMs tags.
+    // Here we only compare one way because the VM can have more (old) tags.
+    for (int key in tagToName.keys) {
+      String nameVm = compareMe.vmTagToName[key];
+      String name = tagToName[key];
+      if (nameVm == name) continue;
+      throw "$key: $nameVm vs $name";
+    }
+    if (tagVersion != compareMe.vmVersion) {
+      throw "Version in tag.dart: $tagVersion; "
+          "version in VM: ${compareMe.vmVersion}";
+    }
+  }
+
+  print("OK");
+}
+
+bool uses8Tags(String name) {
+  return name == "SpecializedVariableGet" ||
+      name == "SpecializedVariableSet" ||
+      name == "SpecializedIntLiteral";
+}
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
+
+class TagCompare {
+  final Map<int, String> mdTagToName;
+  final int mdVersion;
+  final Map<int, String> vmTagToName;
+  final int vmVersion;
+  final Class tagClass;
+
+  TagCompare(this.mdTagToName, this.mdVersion, this.vmTagToName, this.vmVersion,
+      this.tagClass);
+}
diff --git a/pkg/front_end/test/constants/constant_test.dart b/pkg/front_end/test/constants/constant_test.dart
index 7fbee80..6bba0a7 100644
--- a/pkg/front_end/test/constants/constant_test.dart
+++ b/pkg/front_end/test/constants/constant_test.dart
@@ -13,8 +13,8 @@
         InternalCompilerResult,
         DataComputer,
         FormattedMessage,
-        cfeConstantUpdate2018Config,
         createUriForFileName,
+        defaultCfeConfig,
         onFailure,
         runTestFor;
 import 'package:front_end/src/testing/id_testing_utils.dart';
@@ -28,8 +28,7 @@
       supportedMarkers: sharedMarkers,
       createUriForFileName: createUriForFileName,
       onFailure: onFailure,
-      runTest: runTestFor(
-          const ConstantsDataComputer(), [cfeConstantUpdate2018Config]));
+      runTest: runTestFor(const ConstantsDataComputer(), [defaultCfeConfig]));
 }
 
 class ConstantsDataComputer extends DataComputer<String> {
diff --git a/pkg/front_end/test/deps_test.dart b/pkg/front_end/test/deps_test.dart
new file mode 100644
index 0000000..4d9bf2f
--- /dev/null
+++ b/pkg/front_end/test/deps_test.dart
@@ -0,0 +1,144 @@
+import 'dart:io';
+
+import 'package:expect/expect.dart' show Expect;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/fasta/compiler_context.dart';
+import 'package:front_end/src/fasta/dill/dill_target.dart';
+import 'package:front_end/src/fasta/kernel/kernel_target.dart';
+import 'package:front_end/src/fasta/severity.dart';
+import 'package:front_end/src/fasta/ticker.dart';
+import 'package:front_end/src/fasta/uri_translator.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+    show computePlatformBinariesLocation;
+import "package:vm/target/vm.dart" show VmTarget;
+import 'utils/io_utils.dart' show computeRepoDirUri;
+
+final Uri repoDir = computeRepoDirUri();
+
+Set<String> whitelistedExternalDartFiles = {
+  "third_party/pkg/charcode/lib/ascii.dart",
+  "third_party/pkg_tested/package_config/lib/packages.dart",
+  "third_party/pkg_tested/package_config/lib/packages_file.dart",
+  "third_party/pkg_tested/package_config/lib/src/packages_impl.dart",
+  "third_party/pkg_tested/package_config/lib/src/util.dart",
+  // TODO(CFE-team): This file should not be included.
+  // The package isn't even in pubspec.yaml.
+  "pkg/meta/lib/meta.dart",
+};
+
+Future<void> main() async {
+  Ticker ticker = new Ticker(isVerbose: false);
+  CompilerOptions compilerOptions = getOptions();
+
+  Uri dotPackagesUri = repoDir.resolve(".packages");
+  if (!new File.fromUri(dotPackagesUri).existsSync()) {
+    throw "Couldn't find .packages";
+  }
+  compilerOptions.packagesFileUri = dotPackagesUri;
+
+  ProcessedOptions options = new ProcessedOptions(options: compilerOptions);
+
+  Uri frontendLibUri = repoDir.resolve("pkg/front_end/lib/");
+  List<FileSystemEntity> entities =
+      new Directory.fromUri(frontendLibUri).listSync(recursive: true);
+  for (FileSystemEntity entity in entities) {
+    if (entity is File && entity.path.endsWith(".dart")) {
+      options.inputs.add(entity.uri);
+    }
+  }
+
+  List<Uri> result = await CompilerContext.runWithOptions<List<Uri>>(options,
+      (CompilerContext c) async {
+    UriTranslator uriTranslator = await c.options.getUriTranslator();
+    DillTarget dillTarget =
+        new DillTarget(ticker, uriTranslator, c.options.target);
+    KernelTarget kernelTarget =
+        new KernelTarget(c.fileSystem, false, dillTarget, uriTranslator);
+    Uri platform = c.options.sdkSummary;
+    if (platform != null) {
+      var bytes = new File.fromUri(platform).readAsBytesSync();
+      var platformComponent = loadComponentFromBytes(bytes);
+      dillTarget.loader
+          .appendLibraries(platformComponent, byteCount: bytes.length);
+    }
+
+    kernelTarget.setEntryPoints(c.options.inputs);
+    await dillTarget.buildOutlines();
+    await kernelTarget.loader.buildOutlines();
+    return new List<Uri>.from(c.dependencies);
+  });
+
+  Set<Uri> otherDartUris = new Set<Uri>();
+  Set<Uri> otherNonDartUris = new Set<Uri>();
+  Set<Uri> frontEndUris = new Set<Uri>();
+  Set<Uri> kernelUris = new Set<Uri>();
+  Set<Uri> dartPlatformUris = new Set<Uri>();
+  Uri kernelUri = repoDir.resolve("pkg/kernel/");
+  Uri platformUri1 = repoDir.resolve("sdk/lib/");
+  Uri platformUri2 = repoDir.resolve("runtime/lib/");
+  Uri platformUri3 = repoDir.resolve("runtime/bin/");
+  for (Uri uri in result) {
+    if (uri.toString().startsWith(frontendLibUri.toString())) {
+      frontEndUris.add(uri);
+    } else if (uri.toString().startsWith(kernelUri.toString())) {
+      kernelUris.add(uri);
+    } else if (uri.toString().startsWith(platformUri1.toString()) ||
+        uri.toString().startsWith(platformUri2.toString()) ||
+        uri.toString().startsWith(platformUri3.toString())) {
+      dartPlatformUris.add(uri);
+    } else if (uri.toString().endsWith(".dart")) {
+      otherDartUris.add(uri);
+    } else {
+      otherNonDartUris.add(uri);
+    }
+  }
+
+  // * Everything in frontEndUris is okay --- the frontend can import itself.
+  // * Everything in kernel is okay --- the frontend is allowed to
+  //   import package:kernel.
+  // * For other entries, remove whitelisted entries.
+  // * Everything else is an error.
+
+  // Remove white-listed non-dart files.
+  otherNonDartUris.remove(dotPackagesUri);
+  otherNonDartUris.remove(repoDir.resolve("sdk/lib/libraries.json"));
+
+  // Remove white-listed dart files.
+  for (String s in whitelistedExternalDartFiles) {
+    otherDartUris.remove(repoDir.resolve(s));
+  }
+
+  if (otherNonDartUris.isNotEmpty || otherDartUris.isNotEmpty) {
+    print("The following files was imported without being whitelisted:");
+    for (Uri uri in otherNonDartUris) {
+      print(" - $uri");
+    }
+    for (Uri uri in otherDartUris) {
+      print(" - $uri");
+    }
+    exitCode = 1;
+  }
+}
+
+CompilerOptions getOptions() {
+  // Compile sdk because when this is run from a lint it uses the checked-in sdk
+  // and we might not have a suitable compiled platform.dill file.
+  Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+  CompilerOptions options = new CompilerOptions()
+    ..sdkRoot = sdkRoot
+    ..compileSdk = true
+    ..target = new VmTarget(new TargetFlags())
+    ..librariesSpecificationUri = repoDir.resolve("sdk/lib/libraries.json")
+    ..omitPlatform = true
+    ..onDiagnostic = (DiagnosticMessage message) {
+      if (message.severity == Severity.error) {
+        Expect.fail(
+            "Unexpected error: ${message.plainTextFormatted.join('\n')}");
+      }
+    }
+    ..environmentDefines = const {};
+  return options;
+}
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_test.dart
new file mode 100644
index 0000000..d655ac1
--- /dev/null
+++ b/pkg/front_end/test/explicit_creation_test.dart
@@ -0,0 +1,270 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:front_end/src/api_prototype/compiler_options.dart' as api;
+import 'package:front_end/src/api_prototype/file_system.dart' as api;
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+    show computePlatformBinariesLocation;
+import 'package:front_end/src/fasta/builder/builder.dart';
+import 'package:front_end/src/fasta/builder/declaration_builder.dart';
+import 'package:front_end/src/fasta/compiler_context.dart';
+import 'package:front_end/src/fasta/constant_context.dart';
+import 'package:front_end/src/fasta/dill/dill_target.dart';
+import 'package:front_end/src/fasta/fasta_codes.dart' as fasta;
+import 'package:front_end/src/fasta/kernel/body_builder.dart';
+import 'package:front_end/src/fasta/kernel/constness.dart';
+import 'package:front_end/src/fasta/kernel/kernel_target.dart';
+import 'package:front_end/src/fasta/severity.dart';
+import 'package:front_end/src/fasta/source/diet_listener.dart';
+import 'package:front_end/src/fasta/source/source_library_builder.dart';
+import 'package:front_end/src/fasta/source/source_loader.dart';
+import 'package:front_end/src/fasta/source/stack_listener.dart';
+import 'package:front_end/src/fasta/ticker.dart';
+import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
+import 'package:front_end/src/fasta/type_inference/type_inferrer.dart';
+import 'package:front_end/src/fasta/uri_translator.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+import "package:vm/target/vm.dart" show VmTarget;
+
+final Uri repoDir = _computeRepoDir();
+
+Uri _computeRepoDir() {
+  ProcessResult result = Process.runSync(
+      'git', ['rev-parse', '--show-toplevel'],
+      runInShell: true,
+      workingDirectory: new File.fromUri(Platform.script).parent.path);
+  String dirPath = (result.stdout as String).trim();
+  return new Directory(dirPath).uri;
+}
+
+Uri frontendLibUri;
+
+Future<void> main() async {
+  Ticker ticker = new Ticker(isVerbose: false);
+  api.CompilerOptions compilerOptions = getOptions();
+
+  Uri dotPackagesUri = repoDir.resolve(".packages");
+  if (!new File.fromUri(dotPackagesUri).existsSync()) {
+    throw "Couldn't find .packages";
+  }
+  compilerOptions.packagesFileUri = dotPackagesUri;
+
+  ProcessedOptions options = new ProcessedOptions(options: compilerOptions);
+
+  frontendLibUri = repoDir.resolve("pkg/front_end/lib/");
+  List<FileSystemEntity> entities =
+      new Directory.fromUri(frontendLibUri).listSync(recursive: true);
+  for (FileSystemEntity entity in entities) {
+    if (entity is File && entity.path.endsWith(".dart")) {
+      options.inputs.add(entity.uri);
+    }
+  }
+
+  Stopwatch stopwatch = new Stopwatch()..start();
+
+  await CompilerContext.runWithOptions<List<Uri>>(options,
+      (CompilerContext c) async {
+    UriTranslator uriTranslator = await c.options.getUriTranslator();
+    DillTarget dillTarget =
+        new DillTarget(ticker, uriTranslator, c.options.target);
+    KernelTarget kernelTarget =
+        new KernelTargetTest(c.fileSystem, false, dillTarget, uriTranslator);
+
+    Uri platform = c.options.sdkSummary;
+    if (platform != null) {
+      var bytes = new File.fromUri(platform).readAsBytesSync();
+      var platformComponent = loadComponentFromBytes(bytes);
+      dillTarget.loader
+          .appendLibraries(platformComponent, byteCount: bytes.length);
+    }
+
+    kernelTarget.setEntryPoints(c.options.inputs);
+    await dillTarget.buildOutlines();
+    await kernelTarget.buildOutlines();
+    await kernelTarget.buildComponent();
+    return null;
+  });
+
+  print("Done in ${stopwatch.elapsedMilliseconds} ms. "
+      "Found $errorCount errors.");
+}
+
+class KernelTargetTest extends KernelTarget {
+  KernelTargetTest(api.FileSystem fileSystem, bool includeComments,
+      DillTarget dillTarget, UriTranslator uriTranslator)
+      : super(fileSystem, includeComments, dillTarget, uriTranslator);
+
+  @override
+  SourceLoader createLoader() {
+    return new SourceLoaderTest(fileSystem, includeComments, this);
+  }
+}
+
+class SourceLoaderTest extends SourceLoader {
+  SourceLoaderTest(
+      api.FileSystem fileSystem, bool includeComments, KernelTarget target)
+      : super(fileSystem, includeComments, target);
+
+  @override
+  DietListener createDietListener(SourceLibraryBuilder library) {
+    return new DietListenerTest(
+        library, hierarchy, coreTypes, typeInferenceEngine);
+  }
+
+  BodyBuilder createBodyBuilderForOutlineExpression(
+      LibraryBuilder library,
+      DeclarationBuilder declarationBuilder,
+      ModifierBuilder member,
+      Scope scope,
+      Uri fileUri) {
+    return new BodyBuilderTest.forOutlineExpression(
+        library, declarationBuilder, member, scope, fileUri);
+  }
+
+  BodyBuilder createBodyBuilderForField(
+      FieldBuilder field, TypeInferrer typeInferrer) {
+    return new BodyBuilderTest.forField(field, typeInferrer);
+  }
+}
+
+class DietListenerTest extends DietListener {
+  DietListenerTest(SourceLibraryBuilder library, ClassHierarchy hierarchy,
+      CoreTypes coreTypes, TypeInferenceEngine typeInferenceEngine)
+      : super(library, hierarchy, coreTypes, typeInferenceEngine);
+
+  @override
+  StackListener createListenerInternal(
+      ModifierBuilder builder,
+      Scope memberScope,
+      Scope formalParameterScope,
+      bool isDeclarationInstanceMember,
+      VariableDeclaration extensionThis,
+      List<TypeParameter> extensionTypeParameters,
+      TypeInferrer typeInferrer,
+      ConstantContext constantContext) {
+    return new BodyBuilderTest(
+        libraryBuilder: libraryBuilder,
+        member: builder,
+        enclosingScope: memberScope,
+        formalParameterScope: formalParameterScope,
+        hierarchy: hierarchy,
+        coreTypes: coreTypes,
+        declarationBuilder: currentDeclaration,
+        isDeclarationInstanceMember: isDeclarationInstanceMember,
+        extensionThis: extensionThis,
+        extensionTypeParameters: extensionTypeParameters,
+        uri: uri,
+        typeInferrer: typeInferrer)
+      ..constantContext = constantContext;
+  }
+}
+
+class BodyBuilderTest extends BodyBuilder {
+  @override
+  BodyBuilderTest(
+      {libraryBuilder,
+      member,
+      enclosingScope,
+      formalParameterScope,
+      hierarchy,
+      coreTypes,
+      declarationBuilder,
+      isDeclarationInstanceMember,
+      extensionThis,
+      extensionTypeParameters,
+      uri,
+      typeInferrer})
+      : super(
+            libraryBuilder: libraryBuilder,
+            member: member,
+            enclosingScope: enclosingScope,
+            formalParameterScope: formalParameterScope,
+            hierarchy: hierarchy,
+            coreTypes: coreTypes,
+            declarationBuilder: declarationBuilder,
+            isDeclarationInstanceMember: isDeclarationInstanceMember,
+            extensionThis: extensionThis,
+            extensionTypeParameters: extensionTypeParameters,
+            uri: uri,
+            typeInferrer: typeInferrer);
+
+  @override
+  BodyBuilderTest.forField(FieldBuilder field, TypeInferrer typeInferrer)
+      : super.forField(field, typeInferrer);
+
+  @override
+  BodyBuilderTest.forOutlineExpression(
+      SourceLibraryBuilder library,
+      DeclarationBuilder declarationBuilder,
+      ModifierBuilder member,
+      Scope scope,
+      Uri fileUri)
+      : super.forOutlineExpression(
+            library, declarationBuilder, member, scope, fileUri);
+
+  @override
+  Expression buildConstructorInvocation(
+      TypeDeclarationBuilder type,
+      Token nameToken,
+      Token nameLastToken,
+      Arguments arguments,
+      String name,
+      List<UnresolvedType> typeArguments,
+      int charOffset,
+      Constness constness) {
+    Token maybeNewOrConst = nameToken.previous;
+    bool doReport = true;
+    if (maybeNewOrConst is KeywordToken) {
+      if (maybeNewOrConst.lexeme == "new" ||
+          maybeNewOrConst.lexeme == "const") {
+        doReport = false;
+      }
+    } else if (maybeNewOrConst is SimpleToken) {
+      if (maybeNewOrConst.lexeme == "@") {
+        doReport = false;
+      }
+    }
+    if (doReport && !uri.toString().startsWith(frontendLibUri.toString())) {
+      doReport = false;
+    }
+    if (doReport) {
+      addProblem(
+          fasta.templateUnspecified.withArguments("Should use new or const"),
+          nameToken.charOffset,
+          nameToken.length);
+    }
+    return super.buildConstructorInvocation(type, nameToken, nameLastToken,
+        arguments, name, typeArguments, charOffset, constness);
+  }
+}
+
+int errorCount = 0;
+
+api.CompilerOptions getOptions() {
+  // Compile sdk because when this is run from a lint it uses the checked-in sdk
+  // and we might not have a suitable compiled platform.dill file.
+  Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+  api.CompilerOptions options = new api.CompilerOptions()
+    ..sdkRoot = sdkRoot
+    ..compileSdk = true
+    ..target = new VmTarget(new TargetFlags())
+    ..librariesSpecificationUri = repoDir.resolve("sdk/lib/libraries.json")
+    ..omitPlatform = true
+    ..onDiagnostic = (api.DiagnosticMessage message) {
+      if (message.severity == Severity.error) {
+        print(message.plainTextFormatted.join('\n'));
+        errorCount++;
+        exitCode = 1;
+      }
+    }
+    ..environmentDefines = const {};
+  return options;
+}
diff --git a/pkg/front_end/test/extensions/data/ambiguous/lib1.dart b/pkg/front_end/test/extensions/data/ambiguous/lib1.dart
new file mode 100644
index 0000000..ae7f7b6
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/lib1.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[AmbiguousExtension1,AmbiguousExtension2,UnambiguousExtension1]*/
+
+/*class: AmbiguousExtension1:
+ builder-name=AmbiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+  static ambiguousStaticMethod1=AmbiguousExtension1|ambiguousStaticMethod1],
+ extension-name=AmbiguousExtension1,
+ extension-onType=String
+*/
+extension AmbiguousExtension1 on String {
+  /*member: AmbiguousExtension1|ambiguousStaticMethod1:
+   builder-name=ambiguousStaticMethod1,
+   member-name=AmbiguousExtension1|ambiguousStaticMethod1
+  */
+  static void ambiguousStaticMethod1() {}
+}
+
+/*class: AmbiguousExtension2:
+ builder-name=AmbiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+  static unambiguousStaticMethod1=AmbiguousExtension2|unambiguousStaticMethod1],
+ extension-name=AmbiguousExtension2,
+ extension-onType=String
+*/
+extension AmbiguousExtension2 on String {
+  /*member: AmbiguousExtension2|unambiguousStaticMethod1:
+   builder-name=unambiguousStaticMethod1,
+   member-name=AmbiguousExtension2|unambiguousStaticMethod1
+  */
+  static void unambiguousStaticMethod1() {}
+}
+
+/*class: UnambiguousExtension1:
+ builder-name=UnambiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+  static ambiguousStaticMethod2=UnambiguousExtension1|ambiguousStaticMethod2],
+ extension-name=UnambiguousExtension1,
+ extension-onType=String
+*/
+extension UnambiguousExtension1 on String {
+  /*member: UnambiguousExtension1|ambiguousStaticMethod2:
+   builder-name=ambiguousStaticMethod2,
+   member-name=UnambiguousExtension1|ambiguousStaticMethod2
+  */
+  static void ambiguousStaticMethod2() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/ambiguous/lib2.dart b/pkg/front_end/test/extensions/data/ambiguous/lib2.dart
new file mode 100644
index 0000000..5958aa2
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/lib2.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[AmbiguousExtension1,AmbiguousExtension2,UnambiguousExtension2]*/
+
+/*class: AmbiguousExtension1:
+ builder-name=AmbiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+  static ambiguousStaticMethod1=AmbiguousExtension1|ambiguousStaticMethod1],
+ extension-name=AmbiguousExtension1,
+ extension-onType=String
+*/
+extension AmbiguousExtension1 on String {
+  /*member: AmbiguousExtension1|ambiguousStaticMethod1:
+   builder-name=ambiguousStaticMethod1,
+   member-name=AmbiguousExtension1|ambiguousStaticMethod1
+  */
+  static void ambiguousStaticMethod1() {}
+}
+
+/*class: AmbiguousExtension2:
+ builder-name=AmbiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+  static unambiguousStaticMethod2=AmbiguousExtension2|unambiguousStaticMethod2],
+ extension-name=AmbiguousExtension2,
+ extension-onType=String
+*/
+extension AmbiguousExtension2 on String {
+  /*member: AmbiguousExtension2|unambiguousStaticMethod2:
+   builder-name=unambiguousStaticMethod2,
+   member-name=AmbiguousExtension2|unambiguousStaticMethod2
+  */
+  static void unambiguousStaticMethod2() {}
+}
+
+/*class: UnambiguousExtension2:
+ builder-name=UnambiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+  static ambiguousStaticMethod2=UnambiguousExtension2|ambiguousStaticMethod2],
+ extension-name=UnambiguousExtension2,
+ extension-onType=String
+*/
+extension UnambiguousExtension2 on String {
+  /*member: UnambiguousExtension2|ambiguousStaticMethod2:
+   builder-name=ambiguousStaticMethod2,
+   member-name=UnambiguousExtension2|ambiguousStaticMethod2
+  */
+  static void ambiguousStaticMethod2() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/ambiguous/main.dart b/pkg/front_end/test/extensions/data/ambiguous/main.dart
new file mode 100644
index 0000000..f4cef0c
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/main.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[
+ lib1.dart.AmbiguousExtension1,
+ lib1.dart.AmbiguousExtension2,
+ lib1.dart.UnambiguousExtension1,
+ lib2.dart.AmbiguousExtension1,
+ lib2.dart.AmbiguousExtension2,
+ lib2.dart.UnambiguousExtension2]
+*/
+
+import 'lib1.dart';
+import 'lib2.dart';
+
+main() {
+  /*error: errors=['AmbiguousExtension1' is imported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+  AmbiguousExtension1.ambiguousStaticMethod1();
+  /*error: errors=['AmbiguousExtension2' is imported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+  AmbiguousExtension2.unambiguousStaticMethod1();
+  UnambiguousExtension1.ambiguousStaticMethod2();
+  UnambiguousExtension2.ambiguousStaticMethod2();
+}
diff --git a/pkg/front_end/test/extensions/data/explicit_this.dart b/pkg/front_end/test/extensions/data/explicit_this.dart
index b684007..735e7d6 100644
--- a/pkg/front_end/test/extensions/data/explicit_this.dart
+++ b/pkg/front_end/test/extensions/data/explicit_this.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2]*/
+
 class A1 {
   Object field;
   void method1() {}
@@ -13,7 +15,10 @@
  extension-members=[
   method2=A2|method2,
   method3=A2|method3,
-  method4=A2|method4],
+  method4=A2|method4,
+  tearoff method2=A2|get#method2,
+  tearoff method3=A2|get#method3,
+  tearoff method4=A2|get#method4],
  extension-name=A2,
  extension-onType=A1
 */
@@ -26,23 +31,44 @@
   */
   void method2() => this.method1();
 
+  /*member: A2|get#method2:
+   builder-name=method2,
+   builder-params=[#this],
+   member-name=A2|get#method2,
+   member-params=[#this]
+  */
+
   /*member: A2|method3:
    builder-name=method3,
    builder-params=[#this],
    member-name=A2|method3,
    member-params=[#this]
- */
+  */
   Object method3() => this.field;
 
+  /*member: A2|get#method3:
+   builder-name=method3,
+   builder-params=[#this],
+   member-name=A2|get#method3,
+   member-params=[#this]
+  */
+
   /*member: A2|method4:
-     builder-name=method4,
-     builder-params=[#this,o],
-     member-name=A2|method4,
-     member-params=[#this,o]
-    */
+   builder-name=method4,
+   builder-params=[#this,o],
+   member-name=A2|method4,
+   member-params=[#this,o]
+  */
   void method4(Object o) {
     this.field = o;
   }
+
+  /*member: A2|get#method4:
+   builder-name=method4,
+   builder-params=[#this,o],
+   member-name=A2|get#method4,
+   member-params=[#this]
+  */
 }
 
 main() {
diff --git a/pkg/front_end/test/extensions/data/export_unnamed/lib.dart b/pkg/front_end/test/extensions/data/export_unnamed/lib.dart
new file mode 100644
index 0000000..04d4c90
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/export_unnamed/lib.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[NamedExtension,_extension#0]*/
+
+/*class: _extension#0:
+ builder-name=_extension#0,
+ builder-onType=String,
+ extension-members=[static staticMethod=_extension#0|staticMethod],
+ extension-name=_extension#0,
+ extension-onType=String
+*/
+extension on String {
+  /*member: _extension#0|staticMethod:
+   builder-name=staticMethod,
+   member-name=_extension#0|staticMethod
+  */
+  static void staticMethod() {}
+}
+
+/*class: NamedExtension:
+ builder-name=NamedExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=NamedExtension|staticMethod],
+ extension-name=NamedExtension,
+ extension-onType=String
+*/
+extension NamedExtension on String {
+  /*member: NamedExtension|staticMethod:
+    builder-name=staticMethod,
+    member-name=NamedExtension|staticMethod
+  */
+  static void staticMethod() {}
+}
diff --git a/pkg/front_end/test/extensions/data/export_unnamed/main.dart b/pkg/front_end/test/extensions/data/export_unnamed/main.dart
new file mode 100644
index 0000000..01ddd37
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/export_unnamed/main.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[lib.dart.NamedExtension]*/
+
+import 'lib.dart';
+
+main() {
+  NamedExtension.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/extension_on_type_variable.dart b/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
index 44f9af1..0c8613f 100644
--- a/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
+++ b/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
@@ -2,11 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[GeneralGeneric]*/
+
 /*class: GeneralGeneric:
  builder-name=GeneralGeneric,
  builder-onType=T,
  builder-type-params=[T],
- extension-members=[method=GeneralGeneric|method],
+ extension-members=[
+  method=GeneralGeneric|method,
+  tearoff method=GeneralGeneric|get#method],
  extension-name=GeneralGeneric,
  extension-onType=T,
  extension-type-params=[T]
@@ -18,9 +22,18 @@
    builder-type-params=[T],
    member-name=GeneralGeneric|method,
    member-params=[#this],
-   member-type-params=[#T]
+   member-type-params=[T]
   */
   T method() => this;
+
+  /*member: GeneralGeneric|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   builder-type-params=[T],
+   member-name=GeneralGeneric|get#method,
+   member-params=[#this],
+   member-type-params=[T]
+  */
 }
 
 main() {
diff --git a/pkg/front_end/test/extensions/data/implicit_this.dart b/pkg/front_end/test/extensions/data/implicit_this.dart
index 9a9e7de..95e1fb3 100644
--- a/pkg/front_end/test/extensions/data/implicit_this.dart
+++ b/pkg/front_end/test/extensions/data/implicit_this.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2]*/
+
 class A1 {
   Object field;
   void method1() {}
@@ -13,7 +15,10 @@
  extension-members=[
   method2=A2|method2,
   method3=A2|method3,
-  method4=A2|method4],
+  method4=A2|method4,
+  tearoff method2=A2|get#method2,
+  tearoff method3=A2|get#method3,
+  tearoff method4=A2|get#method4],
  extension-name=A2,
  extension-onType=A1
 */
@@ -26,6 +31,12 @@
   */
   void method2() => method1();
 
+  /*member: A2|get#method2:
+   builder-name=method2,
+   builder-params=[#this],
+   member-name=A2|get#method2,member-params=[#this]
+  */
+
   /*member: A2|method3:
    builder-name=method3,
    builder-params=[#this],
@@ -34,6 +45,13 @@
   */
   Object method3() => field;
 
+  /*member: A2|get#method3:
+   builder-name=method3,
+   builder-params=[#this],
+   member-name=A2|get#method3,
+   member-params=[#this]
+  */
+
   /*member: A2|method4:
    builder-name=method4,
    builder-params=[#this,o],
@@ -43,6 +61,13 @@
   void method4(Object o) {
     field = o;
   }
+
+  /*member: A2|get#method4:
+   builder-name=method4,
+   builder-params=[#this,o],
+   member-name=A2|get#method4,
+   member-params=[#this]
+  */
 }
 
 main() {
diff --git a/pkg/front_end/test/extensions/data/instance_members.dart b/pkg/front_end/test/extensions/data/instance_members.dart
index 35463d5..1c02c85 100644
--- a/pkg/front_end/test/extensions/data/instance_members.dart
+++ b/pkg/front_end/test/extensions/data/instance_members.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2,B2]*/
+
 class A1 {}
 
 /*class: A2:
@@ -11,7 +13,11 @@
   method1=A2|method1,
   method2=A2|method2,
   method3=A2|method3,
-  method4=A2|method4],
+  method4=A2|method4,
+  tearoff method1=A2|get#method1,
+  tearoff method2=A2|get#method2,
+  tearoff method3=A2|get#method3,
+  tearoff method4=A2|get#method4],
  extension-name=A2,
  extension-onType=A1
 */
@@ -26,6 +32,13 @@
     return this;
   }
 
+  /*member: A2|get#method1:
+   builder-name=method1,
+   builder-params=[#this],
+   member-name=A2|get#method1,
+   member-params=[#this]
+  */
+
   /*member: A2|method2:
      builder-name=method2,
      builder-params=[#this,o],
@@ -39,6 +52,14 @@
     return this;
   }
 
+  /*member: A2|get#method2:
+   builder-name=method2,
+   builder-params=[#this,o],
+   builder-type-params=[T],
+   member-name=A2|get#method2,
+   member-params=[#this]
+  */
+
   /*member: A2|method3:
      builder-name=method3,
      builder-params=[#this],
@@ -54,6 +75,15 @@
     return this;
   }
 
+  /*member: A2|get#method3:
+   builder-name=method3,
+   builder-params=[#this],
+   builder-pos-params=[o],
+   builder-type-params=[T],
+   member-name=A2|get#method3,
+   member-params=[#this]
+  */
+
   /*member: A2|method4:
      builder-name=method4,
      builder-params=[#this],
@@ -68,6 +98,15 @@
     print(o);
     return this;
   }
+
+  /*member: A2|get#method4:
+   builder-name=method4,
+   builder-named-params=[o],
+   builder-params=[#this],
+   builder-type-params=[T],
+   member-name=A2|get#method4,
+   member-params=[#this]
+  */
 }
 
 class B1<T> {}
@@ -78,7 +117,9 @@
  builder-type-params=[T],
  extension-members=[
   method1=B2|method1,
-  method2=B2|method2],
+  method2=B2|method2,
+  tearoff method1=B2|get#method1,
+  tearoff method2=B2|get#method2],
  extension-name=B2,
  extension-onType=B1<T>,
  extension-type-params=[T]
@@ -90,24 +131,42 @@
      builder-type-params=[T],
      member-name=B2|method1,
      member-params=[#this],
-     member-type-params=[#T]
+     member-type-params=[T]
   */
   B1<T> method1() {
     return this;
   }
 
+  /*member: B2|get#method1:
+   builder-name=method1,
+   builder-params=[#this],
+   builder-type-params=[T],
+   member-name=B2|get#method1,
+   member-params=[#this],
+   member-type-params=[T]
+  */
+
   /*member: B2|method2:
      builder-name=method2,
      builder-params=[#this,o],
      builder-type-params=[T,S],
      member-name=B2|method2,
      member-params=[#this,o],
-     member-type-params=[#T,S]
+     member-type-params=[T,S]
   */
   B1<T> method2<S>(S o) {
     print(o);
     return this;
   }
+
+  /*member: B2|get#method2:
+   builder-name=method2,
+   builder-params=[#this,o],
+   builder-type-params=[T,S],
+   member-name=B2|get#method2,
+   member-params=[#this],
+   member-type-params=[T]
+  */
 }
 
 main() {}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/named_declarations.dart b/pkg/front_end/test/extensions/data/named_declarations.dart
index c9e7c08..fa16eec 100644
--- a/pkg/front_end/test/extensions/data/named_declarations.dart
+++ b/pkg/front_end/test/extensions/data/named_declarations.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2,B2,B3,B4]*/
+
 class A1 {}
 
 /*class: A2:
diff --git a/pkg/front_end/test/extensions/data/other_kinds.dart b/pkg/front_end/test/extensions/data/other_kinds.dart
index 72f4547..cab0879 100644
--- a/pkg/front_end/test/extensions/data/other_kinds.dart
+++ b/pkg/front_end/test/extensions/data/other_kinds.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2]*/
+
 class A1 {
   int _instanceField;
   int getInstanceField() => _instanceField;
diff --git a/pkg/front_end/test/extensions/data/reexport/lib.dart b/pkg/front_end/test/extensions/data/reexport/lib.dart
new file mode 100644
index 0000000..f38ec65
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'lib1.dart';
+/*error: errors=['ClashingExtension' is exported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+export 'lib2.dart';
diff --git a/pkg/front_end/test/extensions/data/reexport/lib1.dart b/pkg/front_end/test/extensions/data/reexport/lib1.dart
new file mode 100644
index 0000000..d3529cb
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib1.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[ClashingExtension,UniqueExtension1]*/
+
+/*class: ClashingExtension:
+ builder-name=ClashingExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=ClashingExtension|staticMethod],
+ extension-name=ClashingExtension,
+ extension-onType=String
+*/
+extension ClashingExtension on String {
+  /*member: ClashingExtension|staticMethod:
+   builder-name=staticMethod,
+   member-name=ClashingExtension|staticMethod
+  */
+  static staticMethod() {}
+}
+
+
+/*class: UniqueExtension1:
+ builder-name=UniqueExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=UniqueExtension1|staticMethod],
+ extension-name=UniqueExtension1,
+ extension-onType=String
+*/
+extension UniqueExtension1 on String {
+  /*member: UniqueExtension1|staticMethod:
+   builder-name=staticMethod,
+   member-name=UniqueExtension1|staticMethod
+  */
+  static staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/reexport/lib2.dart b/pkg/front_end/test/extensions/data/reexport/lib2.dart
new file mode 100644
index 0000000..b0d9665
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib2.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[ClashingExtension,UniqueExtension2]*/
+
+/*class: ClashingExtension:
+ builder-name=ClashingExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=ClashingExtension|staticMethod],
+ extension-name=ClashingExtension,
+ extension-onType=String
+*/
+extension ClashingExtension on String {
+  /*member: ClashingExtension|staticMethod:
+   builder-name=staticMethod,
+   member-name=ClashingExtension|staticMethod
+  */
+  static staticMethod() {}
+}
+
+/*class: UniqueExtension2:
+ builder-name=UniqueExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=UniqueExtension2|staticMethod],
+ extension-name=UniqueExtension2,
+ extension-onType=String
+*/
+extension UniqueExtension2 on String {
+  /*member: UniqueExtension2|staticMethod:
+   builder-name=staticMethod,
+   member-name=UniqueExtension2|staticMethod
+  */
+  static staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/reexport/main.dart b/pkg/front_end/test/extensions/data/reexport/main.dart
new file mode 100644
index 0000000..b5c8603
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/main.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[lib1.dart.UniqueExtension1,lib2.dart.UniqueExtension2]*/
+
+import 'lib.dart';
+
+main() {
+  /*error: errors=['ClashingExtension' is exported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+  ClashingExtension.staticMethod();
+  UniqueExtension1.staticMethod();
+  UniqueExtension2.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/show_hide/lib1.dart b/pkg/front_end/test/extensions/data/show_hide/lib1.dart
new file mode 100644
index 0000000..7790aeb
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/lib1.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[HiddenExtension1,ShownExtension1]*/
+
+/*class: ShownExtension1:
+ builder-name=ShownExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=ShownExtension1|staticMethod],
+ extension-name=ShownExtension1,
+ extension-onType=String
+*/
+extension ShownExtension1 on String {
+  /*member: ShownExtension1|staticMethod:
+   builder-name=staticMethod,
+   member-name=ShownExtension1|staticMethod
+  */
+  static void staticMethod() {}
+}
+
+/*class: HiddenExtension1:
+ builder-name=HiddenExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=HiddenExtension1|staticMethod],
+ extension-name=HiddenExtension1,
+ extension-onType=String
+*/
+extension HiddenExtension1 on String {
+  /*member: HiddenExtension1|staticMethod:
+   builder-name=staticMethod,
+   member-name=HiddenExtension1|staticMethod
+  */
+  static void staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/show_hide/lib2.dart b/pkg/front_end/test/extensions/data/show_hide/lib2.dart
new file mode 100644
index 0000000..5c9d793
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/lib2.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[HiddenExtension2,ShownExtension2]*/
+
+/*class: HiddenExtension2:
+ builder-name=HiddenExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=HiddenExtension2|staticMethod],
+ extension-name=HiddenExtension2,
+ extension-onType=String
+*/
+extension HiddenExtension2 on String {
+  /*member: HiddenExtension2|staticMethod:
+   builder-name=staticMethod,
+   member-name=HiddenExtension2|staticMethod
+  */
+  static void staticMethod() {}
+}
+
+/*class: ShownExtension2:
+ builder-name=ShownExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=ShownExtension2|staticMethod],
+ extension-name=ShownExtension2,
+ extension-onType=String
+*/
+extension ShownExtension2 on String {
+  /*member: ShownExtension2|staticMethod:
+   builder-name=staticMethod,
+   member-name=ShownExtension2|staticMethod
+  */
+  static void staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/show_hide/main.dart b/pkg/front_end/test/extensions/data/show_hide/main.dart
new file mode 100644
index 0000000..2e2e978
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: scope=[lib1.dart.ShownExtension1,lib2.dart.ShownExtension2]*/
+
+import 'lib1.dart' show ShownExtension1;
+import 'lib2.dart' hide HiddenExtension2;
+
+main() {
+  ShownExtension1.staticMethod();
+  /*error: errors=[Getter not found: 'HiddenExtension1'.]*/
+  HiddenExtension1.staticMethod();
+  ShownExtension2.staticMethod();
+  /*error: errors=[Getter not found: 'HiddenExtension2'.]*/
+  HiddenExtension2.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/static_members.dart b/pkg/front_end/test/extensions/data/static_members.dart
index aeda9d9..cd426fa 100644
--- a/pkg/front_end/test/extensions/data/static_members.dart
+++ b/pkg/front_end/test/extensions/data/static_members.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2,B2]*/
+
 class A1 {}
 
 /*class: A2:
diff --git a/pkg/front_end/test/extensions/data/super.dart b/pkg/front_end/test/extensions/data/super.dart
index 21bd03a..a4d838d 100644
--- a/pkg/front_end/test/extensions/data/super.dart
+++ b/pkg/front_end/test/extensions/data/super.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2]*/
+
 class A1 {
   method1() {}
 }
@@ -9,7 +11,9 @@
 /*class: A2:
  builder-name=A2,
  builder-onType=A1,
- extension-members=[method2=A2|method2],
+ extension-members=[
+  method2=A2|method2,
+  tearoff method2=A2|get#method2],
  extension-name=A2,
  extension-onType=A1
 */
@@ -23,6 +27,13 @@
   method2() {
     /*error: errors=[SuperAsIdentifier]*/ super.method1();
   }
+
+  /*member: A2|get#method2:
+   builder-name=method2,
+   builder-params=[#this],
+   member-name=A2|get#method2,
+   member-params=[#this]
+  */
 }
 
 main() {
diff --git a/pkg/front_end/test/extensions/data/type_variables.dart b/pkg/front_end/test/extensions/data/type_variables.dart
index 9283d71..5a421a1 100644
--- a/pkg/front_end/test/extensions/data/type_variables.dart
+++ b/pkg/front_end/test/extensions/data/type_variables.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2,A3,A4]*/
+
 class A1<T> {}
 
 /*class: A2:
@@ -10,7 +12,9 @@
  builder-type-params=[T],
  extension-members=[
   method1=A2|method1,
-  method2=A2|method2],
+  method2=A2|method2,
+  tearoff method1=A2|get#method1,
+  tearoff method2=A2|get#method2],
  extension-name=A2,
  extension-onType=A1<T>,
  extension-type-params=[T]
@@ -22,27 +26,84 @@
      builder-type-params=[T,S extends T],
      member-name=A2|method1,
      member-params=[#this],
-     member-type-params=[#T,S extends #T]
+     member-type-params=[T,S extends T]
   */
   A1<T> method1<S extends T>() {
     return this;
   }
 
+  /*member: A2|get#method1:
+   builder-name=method1,
+   builder-params=[#this],
+   builder-type-params=[T,S extends T],
+   member-name=A2|get#method1,
+   member-params=[#this],
+   member-type-params=[T]
+  */
+
   /*member: A2|method2:
      builder-name=method2,
      builder-params=[#this,o],
      builder-type-params=[T,S extends A1<T>],
      member-name=A2|method2,
      member-params=[#this,o],
-     member-type-params=[#T,S extends A1<#T>]
+     member-type-params=[T,S extends A1<T>]
   */
   A1<T> method2<S extends A1<T>>(S o) {
     print(o);
     return this;
   }
+
+  /*member: A2|get#method2:
+   builder-name=method2,
+   builder-params=[#this,o],
+   builder-type-params=[T,S extends A1<T>],
+   member-name=A2|get#method2,
+   member-params=[#this],
+   member-type-params=[T]
+  */
 }
 
-// TODO(johnniwinther): Support F-bounded extensions. Currently the type
-// variable is not recognized as a type within the bound.
+/*class: A3:
+ builder-name=A3,
+ builder-onType=A1<T>,
+ builder-type-params=[T extends A1<T>],
+ extension-name=A3,
+ extension-onType=A1<T>,
+ extension-type-params=[T extends A1<T>]
+*/
+extension A3<T extends A1<T>> on A1<T> {
+}
+
+/*class: A4:
+ builder-name=A4,
+ builder-onType=A1<T>,
+ builder-type-params=[T],
+ extension-members=[
+  method=A4|method,
+  tearoff method=A4|get#method],
+ extension-name=A4,
+ extension-onType=A1<T>,
+ extension-type-params=[T]
+*/
+extension A4<T> on A1<T> {
+  /*member: A4|method:
+   builder-name=method,
+   builder-params=[#this],
+   builder-type-params=[T,T],
+   member-name=A4|method,
+   member-params=[#this],
+   member-type-params=[#T,T]*/
+  method<T>() {}
+
+  /*member: A4|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   builder-type-params=[T,T],
+   member-name=A4|get#method,
+   member-params=[#this],
+   member-type-params=[#T]
+  */
+}
 
 main() {}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/unnamed_declarations.dart b/pkg/front_end/test/extensions/data/unnamed_declarations.dart
index d36cf3d..eab0143 100644
--- a/pkg/front_end/test/extensions/data/unnamed_declarations.dart
+++ b/pkg/front_end/test/extensions/data/unnamed_declarations.dart
@@ -2,101 +2,152 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[_extension#0,_extension#1,_extension#2,_extension#3,_extension#4]*/
+
 class A1 {}
 
-/*class: extension#0:
- builder-name=extension#0,
+/*class: _extension#0:
+ builder-name=_extension#0,
  builder-onType=A1,
- extension-members=[method=extension#0|method],
- extension-name=extension#0,
+ extension-members=[
+  method=_extension#0|method,
+  tearoff method=_extension#0|get#method],
+ extension-name=_extension#0,
  extension-onType=A1
 */
 extension on A1 {
-  /*member: extension#0|method:
+  /*member: _extension#0|method:
      builder-name=method,
      builder-params=[#this],
-     member-name=extension#0|method,
+     member-name=_extension#0|method,
      member-params=[#this]
   */
   method() {}
+
+  /*member: _extension#0|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   member-name=_extension#0|get#method,
+   member-params=[#this]
+  */
 }
 
-/*class: extension#1:
- builder-name=extension#1,
+/*class: _extension#1:
+ builder-name=_extension#1,
  builder-onType=A1,
- extension-members=[method=extension#1|method],
- extension-name=extension#1,
+ extension-members=[
+  method=_extension#1|method,
+  tearoff method=_extension#1|get#method],
+ extension-name=_extension#1,
  extension-onType=A1
 */
 extension on A1 {
-  /*member: extension#1|method:
+  /*member: _extension#1|method:
      builder-name=method,
      builder-params=[#this],
-     member-name=extension#1|method,
+     member-name=_extension#1|method,
      member-params=[#this]
   */
   method() {}
+
+  /*member: _extension#1|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   member-name=_extension#1|get#method,
+   member-params=[#this]
+  */
 }
 
 class B1<T> {}
 
-/*class: extension#2:
- builder-name=extension#2,
+/*class: _extension#2:
+ builder-name=_extension#2,
  builder-onType=B1<T>,
  builder-type-params=[T],
- extension-members=[method=extension#2|method],
- extension-name=extension#2,
+ extension-members=[
+  method=_extension#2|method,
+  tearoff method=_extension#2|get#method],
+ extension-name=_extension#2,
  extension-onType=B1<T>,
  extension-type-params=[T]
 */
 extension <T> on B1<T> {
-  /*member: extension#2|method:
+  /*member: _extension#2|method:
      builder-name=method,
      builder-params=[#this],
      builder-type-params=[T],
-     member-name=extension#2|method,
+     member-name=_extension#2|method,
      member-params=[#this],
-     member-type-params=[#T]
+     member-type-params=[T]
   */
   method() {}
+
+  /*member: _extension#2|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   builder-type-params=[T],
+   member-name=_extension#2|get#method,
+   member-params=[#this],
+   member-type-params=[T]
+  */
 }
 
-/*class: extension#3:
- builder-name=extension#3,
+/*class: _extension#3:
+ builder-name=_extension#3,
  builder-onType=B1<A1>,
- extension-members=[method=extension#3|method],
- extension-name=extension#3,
+ extension-members=[
+  method=_extension#3|method,
+  tearoff method=_extension#3|get#method],
+ extension-name=_extension#3,
  extension-onType=B1<A1>
 */
 extension on B1<A1> {
-  /*member: extension#3|method:
+  /*member: _extension#3|method:
      builder-name=method,
      builder-params=[#this],
-     member-name=extension#3|method,
+     member-name=_extension#3|method,
      member-params=[#this]
   */
   method() {}
+
+  /*member: _extension#3|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   member-name=_extension#3|get#method,
+   member-params=[#this]
+  */
 }
 
-/*class: extension#4:
- builder-name=extension#4,
+/*class: _extension#4:
+ builder-name=_extension#4,
  builder-onType=B1<T>,
  builder-type-params=[T extends A1],
- extension-members=[method=extension#4|method],
- extension-name=extension#4,
+ extension-members=[
+  method=_extension#4|method,
+  tearoff method=_extension#4|get#method],
+ extension-name=_extension#4,
  extension-onType=B1<T>,
  extension-type-params=[T extends A1]
 */
 extension <T extends A1> on B1<T> {
-  /*member: extension#4|method:
+  /*member: _extension#4|method:
      builder-name=method,
      builder-params=[#this],
      builder-type-params=[T extends A1],
-     member-name=extension#4|method,
+     member-name=_extension#4|method,
      member-params=[#this],
-     member-type-params=[#T extends A1]
+     member-type-params=[T extends A1]
   */
   method() {}
+
+  /*member: _extension#4|get#method:
+   builder-name=method,
+   builder-params=[#this],
+   builder-type-params=[T extends A1],
+   member-name=_extension#4|get#method,
+   member-params=[#this],
+   member-type-params=[T extends A1]
+  */
 }
 
 main() {}
diff --git a/pkg/front_end/test/extensions/data/use_as_type.dart b/pkg/front_end/test/extensions/data/use_as_type.dart
index f9e9b1d..6f411ab 100644
--- a/pkg/front_end/test/extensions/data/use_as_type.dart
+++ b/pkg/front_end/test/extensions/data/use_as_type.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/*library: scope=[A2,B2]*/
+
 class A1 {}
 
 /*class: A2:
diff --git a/pkg/front_end/test/extensions/extensions_test.dart b/pkg/front_end/test/extensions/extensions_test.dart
index 298ec22..33e8fb4 100644
--- a/pkg/front_end/test/extensions/extensions_test.dart
+++ b/pkg/front_end/test/extensions/extensions_test.dart
@@ -43,6 +43,13 @@
     new ExtensionsDataExtractor(compilerResult, actualMap).computeForClass(cls);
   }
 
+  void computeLibraryData(InternalCompilerResult compilerResult,
+      Library library, Map<Id, ActualData<Features>> actualMap,
+      {bool verbose}) {
+    new ExtensionsDataExtractor(compilerResult, actualMap)
+        .computeForLibrary(library);
+  }
+
   @override
   void computeExtensionData(InternalCompilerResult compilerResult,
       Extension extension, Map<Id, ActualData<Features>> actualMap,
@@ -84,6 +91,7 @@
   static const String builderRequiredParameters = 'builder-params';
   static const String builderPositionalParameters = 'builder-pos-params';
   static const String builderNamedParameters = 'builder-named-params';
+  static const String builderScope = 'scope';
 
   static const String clsName = 'cls-name';
   static const String clsTypeParameters = 'cls-type-params';
@@ -112,6 +120,22 @@
       : super(compilerResult, actualMap);
 
   @override
+  Features computeLibraryValue(Id id, Library library) {
+    Features features = new Features();
+    LibraryBuilder libraryBuilder =
+        lookupLibraryBuilder(compilerResult, library);
+    libraryBuilder.scope.forEachExtension((ExtensionBuilder extension) {
+      LibraryBuilder library = extension.parent;
+      String libraryPrefix = '';
+      if (library != libraryBuilder) {
+        libraryPrefix = '${library.fileUri.pathSegments.last}.';
+      }
+      features.addElement(Tags.builderScope, '$libraryPrefix${extension.name}');
+    });
+    return features;
+  }
+
+  @override
   Features computeClassValue(Id id, Class cls) {
     ClassBuilder clsBuilder = lookupClassBuilder(compilerResult, cls);
     if (!clsBuilder.isExtension) {
diff --git a/pkg/front_end/test/fasta/expression_test.dart b/pkg/front_end/test/fasta/expression_test.dart
index 40ccfb4..8366fcb 100644
--- a/pkg/front_end/test/fasta/expression_test.dart
+++ b/pkg/front_end/test/fasta/expression_test.dart
@@ -10,16 +10,6 @@
 
 import "dart:io" show File, IOSink;
 
-import "package:kernel/ast.dart"
-    show Procedure, Component, DynamicType, DartType, TypeParameter;
-
-import "package:testing/testing.dart"
-    show Chain, ChainContext, Result, Step, TestDescription, runMe;
-
-import "package:testing/src/log.dart" show splitLines;
-
-import "package:yaml/yaml.dart" show YamlMap, YamlList, loadYamlNode;
-
 import "package:front_end/src/api_prototype/compiler_options.dart"
     show CompilerOptions, DiagnosticMessage;
 
@@ -29,31 +19,41 @@
 import "package:front_end/src/api_prototype/terminal_color_support.dart"
     show printDiagnosticMessage;
 
+import 'package:front_end/src/base/processed_options.dart'
+    show ProcessedOptions;
+
 import 'package:front_end/src/compute_platform_binaries_location.dart'
     show computePlatformBinariesLocation;
 
 import 'package:front_end/src/external_state_snapshot.dart'
     show ExternalStateSnapshot;
 
-import 'package:front_end/src/base/processed_options.dart'
-    show ProcessedOptions;
-
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
 import 'package:front_end/src/fasta/incremental_compiler.dart'
     show IncrementalCompiler;
 
+import "package:kernel/ast.dart"
+    show Procedure, Component, DynamicType, DartType, TypeParameter;
+
 import 'package:kernel/target/targets.dart' show TargetFlags;
 
 import 'package:kernel/text/ast_to_text.dart' show Printer;
 
+import "package:testing/src/log.dart" show splitLines;
+
+import "package:testing/testing.dart"
+    show Chain, ChainContext, Result, Step, TestDescription, runMe;
+
 import 'package:vm/target/vm.dart' show VmTarget;
 
-import '../../lib/src/fasta/testing/kernel_chain.dart' show runDiff, openWrite;
+import "package:yaml/yaml.dart" show YamlMap, YamlList, loadYamlNode;
 
 import '../../lib/src/fasta/kernel/utils.dart'
     show writeComponentToFile, serializeProcedure;
 
+import '../utils/kernel_chain.dart' show runDiff, openWrite;
+
 const JsonEncoder json = const JsonEncoder.withIndent("  ");
 
 class Context extends ChainContext {
@@ -388,12 +388,12 @@
   final Uri entryPoint = base.resolve("nothing.dart");
 
   /// The custom URI used to locate the dill file in the MemoryFileSystem.
-  final Uri sdkSummary = base.resolve("vm_platform.dill");
+  final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
 
   /// The actual location of the dill file.
   final Uri sdkSummaryFile =
       computePlatformBinariesLocation(forceBuildDir: true)
-          .resolve("vm_platform.dill");
+          .resolve("vm_platform_strong.dill");
 
   final MemoryFileSystem fs = new MemoryFileSystem(base);
 
@@ -433,4 +433,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/fast_strong_test.dart b/pkg/front_end/test/fasta/fast_strong_test.dart
index 6c1464c..26c0875 100644
--- a/pkg/front_end/test/fasta/fast_strong_test.dart
+++ b/pkg/front_end/test/fasta/fast_strong_test.dart
@@ -18,4 +18,5 @@
 }
 
 main([List<String> arguments = const []]) => runMe(arguments, createContext,
-    "../../testing.json", Platform.script.resolve("strong_test.dart"));
+    configurationPath: "../../testing.json",
+    me: Platform.script.resolve("strong_tester.dart"));
diff --git a/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
new file mode 100644
index 0000000..887559e
--- /dev/null
+++ b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
@@ -0,0 +1,104 @@
+// 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:front_end/src/fasta/flow_analysis/flow_analysis.dart';
+import 'package:test/test.dart';
+
+main() {
+  test('capturedAnywhere records assignments in closures', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    var v3 = _Variable('v3');
+    assignedVariables.write(v1);
+    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.write(v2);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.write(v3);
+    expect(assignedVariables.capturedAnywhere, {v2});
+  });
+
+  test('writtenInNode ignores assignments outside the node', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    assignedVariables.write(v1);
+    assignedVariables.beginNode();
+    var node = _Node();
+    assignedVariables.endNode(node);
+    assignedVariables.write(v2);
+    expect(assignedVariables.writtenInNode(node), isEmpty);
+  });
+
+  test('writtenInNode records assignments inside the node', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    assignedVariables.beginNode();
+    assignedVariables.write(v1);
+    var node = _Node();
+    assignedVariables.endNode(node);
+    expect(assignedVariables.writtenInNode(node), {v1});
+  });
+
+  test('writtenInNode records assignments in a nested node', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    assignedVariables.beginNode();
+    assignedVariables.beginNode();
+    assignedVariables.write(v1);
+    assignedVariables.endNode(_Node());
+    var node = _Node();
+    assignedVariables.endNode(node);
+    expect(assignedVariables.writtenInNode(node), {v1});
+  });
+
+  test('writtenInNode records assignments in a closure', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.write(v1);
+    var node = _Node();
+    assignedVariables.endNode(node, isClosure: true);
+    expect(assignedVariables.writtenInNode(node), {v1});
+  });
+
+  test('capturedInNode ignores assignments in non-nested closures', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.write(v1);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.beginNode();
+    var node = _Node();
+    assignedVariables.endNode(node);
+    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.write(v2);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    expect(assignedVariables.capturedInNode(node), isEmpty);
+  });
+
+  test('capturedInNode records assignments in nested closures', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    assignedVariables.beginNode();
+    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.write(v1);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    var node = _Node();
+    assignedVariables.endNode(node);
+    expect(assignedVariables.capturedInNode(node), {v1});
+  });
+}
+
+class _Node {}
+
+class _Variable {
+  final String name;
+
+  _Variable(this.name);
+
+  @override
+  String toString() => name;
+}
diff --git a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
index ba4bae0..26fa4ca 100644
--- a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
+++ b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
@@ -3,51 +3,60 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart';
+import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 
 main() {
   group('API', () {
     test('conditional_thenBegin promotes true branch', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.conditional_thenBegin(h.notNull(x)());
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.conditional_elseBegin(_Expression());
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.conditional_end(_Expression(), _Expression());
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.conditional_thenBegin(h.notNull(x)());
+        expect(flow.promotedType(x).type, 'int');
+        flow.conditional_elseBegin(_Expression());
+        expect(flow.promotedType(x), isNull);
+        flow.conditional_end(_Expression(), _Expression());
+        expect(flow.promotedType(x), isNull);
+      });
     });
 
     test('conditional_elseBegin promotes false branch', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.conditional_thenBegin(h.eqNull(x)());
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.conditional_elseBegin(_Expression());
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.conditional_end(_Expression(), _Expression());
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.conditional_thenBegin(h.eqNull(x)());
+        expect(flow.promotedType(x), isNull);
+        flow.conditional_elseBegin(_Expression());
+        expect(flow.promotedType(x).type, 'int');
+        flow.conditional_end(_Expression(), _Expression());
+        expect(flow.promotedType(x), isNull);
+      });
     });
 
     test('conditional_end keeps promotions common to true and false branches',
         () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('x', 'int?');
-      var z = h.addAssignedVar('x', 'int?');
-      h.flow.conditional_thenBegin(_Expression());
-      h.promote(x, 'int');
-      h.promote(y, 'int');
-      h.flow.conditional_elseBegin(_Expression());
-      h.promote(x, 'int');
-      h.promote(z, 'int');
-      h.flow.conditional_end(_Expression(), _Expression());
-      expect(h.flow.promotedType(x).type, 'int');
-      expect(h.flow.promotedType(y), isNull);
-      expect(h.flow.promotedType(z), isNull);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        flow.conditional_thenBegin(_Expression());
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        flow.conditional_elseBegin(_Expression());
+        h.promote(x, 'int');
+        h.promote(z, 'int');
+        flow.conditional_end(_Expression(), _Expression());
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
+      });
     });
 
     test('conditional joins true states', () {
@@ -55,17 +64,21 @@
       //   promotes x, but not y or z
       // }
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      var z = h.addAssignedVar('z', 'int?');
-      h.if_(
-          h.conditional(h.expr, h.and(h.notNull(x), h.notNull(y)),
-              h.and(h.notNull(x), h.notNull(z))), () {
-        expect(h.flow.promotedType(x).type, 'int');
-        expect(h.flow.promotedType(y), isNull);
-        expect(h.flow.promotedType(z), isNull);
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        h.if_(
+            h.conditional(h.expr, h.and(h.notNull(x), h.notNull(y)),
+                h.and(h.notNull(x), h.notNull(z))), () {
+          expect(flow.promotedType(x).type, 'int');
+          expect(flow.promotedType(y), isNull);
+          expect(flow.promotedType(z), isNull);
+        });
       });
-      h.flow.finish();
     });
 
     test('conditional joins false states', () {
@@ -74,134 +87,183 @@
       //   promotes x, but not y or z
       // }
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      var z = h.addAssignedVar('z', 'int?');
-      h.ifElse(
-          h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
-              h.or(h.eqNull(x), h.eqNull(z))),
-          () {}, () {
-        expect(h.flow.promotedType(x).type, 'int');
-        expect(h.flow.promotedType(y), isNull);
-        expect(h.flow.promotedType(z), isNull);
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        h.ifElse(
+            h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
+                h.or(h.eqNull(x), h.eqNull(z))),
+            () {}, () {
+          expect(flow.promotedType(x).type, 'int');
+          expect(flow.promotedType(y), isNull);
+          expect(flow.promotedType(z), isNull);
+        });
       });
-      h.flow.finish();
     });
 
     test('conditionEqNull(notEqual: true) promotes true branch', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var expr = _Expression();
-      h.flow.conditionEqNull(expr, x, notEqual: true);
-      h.flow.ifStatement_thenBegin(expr);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.ifStatement_elseBegin();
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.ifStatement_end(true);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var expr = _Expression();
+        flow.conditionEqNull(expr, x, notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_end(true);
+      });
     });
 
     test('conditionEqNull(notEqual: false) promotes false branch', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var expr = _Expression();
-      h.flow.conditionEqNull(expr, x, notEqual: false);
-      h.flow.ifStatement_thenBegin(expr);
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.ifStatement_elseBegin();
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.ifStatement_end(true);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var expr = _Expression();
+        flow.conditionEqNull(expr, x, notEqual: false);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_end(true);
+      });
     });
 
     test('doStatement_bodyBegin() un-promotes', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.promote(x, 'int');
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.doStatement_bodyBegin(_Statement(), {x});
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.doStatement_conditionBegin();
-      h.flow.doStatement_end(_Expression());
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.doStatement_bodyBegin(_Statement(), {x});
+        expect(flow.promotedType(x), isNull);
+        flow.doStatement_conditionBegin();
+        flow.doStatement_end(_Expression());
+      });
     });
 
     test('doStatement_conditionBegin() joins continue state', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var stmt = _Statement();
-      h.flow.doStatement_bodyBegin(stmt, {});
-      h.if_(h.notNull(x), () {
-        h.flow.handleContinue(stmt);
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var stmt = _Statement();
+        flow.doStatement_bodyBegin(stmt, {});
+        h.if_(h.notNull(x), () {
+          flow.handleContinue(stmt);
+        });
+        flow.handleExit();
+        expect(flow.isReachable, false);
+        expect(flow.promotedType(x), isNull);
+        flow.doStatement_conditionBegin();
+        expect(flow.isReachable, true);
+        expect(flow.promotedType(x).type, 'int');
+        flow.doStatement_end(_Expression());
       });
-      h.flow.handleExit();
-      expect(h.flow.isReachable, false);
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.doStatement_conditionBegin();
-      expect(h.flow.isReachable, true);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.doStatement_end(_Expression());
-      h.flow.finish();
     });
 
     test('doStatement_end() promotes', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.doStatement_bodyBegin(_Statement(), {});
-      h.flow.doStatement_conditionBegin();
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.doStatement_end(h.eqNull(x)());
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.doStatement_bodyBegin(_Statement(), {});
+        flow.doStatement_conditionBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.doStatement_end(h.eqNull(x)());
+        expect(flow.promotedType(x).type, 'int');
+      });
     });
 
     test('finish checks proper nesting', () {
       var h = _Harness();
       var expr = _Expression();
-      h.flow.ifStatement_thenBegin(expr);
-      expect(() => h.flow.finish(), _asserts);
+      var flow = h.createFlow();
+      flow.ifStatement_thenBegin(expr);
+      expect(() => flow.finish(), _asserts);
     });
 
     test('finish checks for un-added variables', () {
       var h = _Harness();
       var x = _Var('x', _Type('int'));
-      h.flow.isAssigned(x);
-      expect(() => h.flow.finish(), _asserts);
+      var flow = h.createFlow();
+      flow.isAssigned(x);
+      expect(() => flow.finish(), _asserts);
     });
 
     test('for_conditionBegin() un-promotes', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.promote(x, 'int');
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.for_conditionBegin({x});
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.for_bodyBegin(_Statement(), _Expression());
-      h.flow.for_updaterBegin();
-      h.flow.for_end();
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.for_conditionBegin({x});
+        expect(flow.promotedType(x), isNull);
+        flow.for_bodyBegin(_Statement(), _Expression());
+        flow.for_updaterBegin();
+        flow.for_end();
+      });
+    });
+
+    test('for_conditionBegin() handles not-yet-seen variables', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.for_conditionBegin({x});
+        flow.add(x, assigned: true);
+        flow.for_bodyBegin(_Statement(), _Expression());
+        flow.for_updaterBegin();
+        flow.for_end();
+      });
+    });
+
+    test('for_bodyBegin() handles empty condition', () {
+      var h = _Harness();
+      h.run((flow) {
+        flow.for_conditionBegin({});
+        flow.for_bodyBegin(_Statement(), null);
+        flow.for_updaterBegin();
+        expect(flow.isReachable, isTrue);
+        flow.for_end();
+        expect(flow.isReachable, isFalse);
+      });
     });
 
     test('for_bodyBegin() promotes', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.for_conditionBegin({});
-      h.flow.for_bodyBegin(_Statement(), h.notNull(x)());
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.for_updaterBegin();
-      h.flow.for_end();
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.for_conditionBegin({});
+        flow.for_bodyBegin(_Statement(), h.notNull(x)());
+        expect(flow.promotedType(x).type, 'int');
+        flow.for_updaterBegin();
+        flow.for_end();
+      });
     });
 
     test('for_bodyBegin() can be used with a null statement', () {
       // This is needed for collection elements that are for-loops.
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.for_conditionBegin({});
-      h.flow.for_bodyBegin(null, h.notNull(x)());
-      h.flow.for_updaterBegin();
-      h.flow.for_end();
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.for_conditionBegin({});
+        flow.for_bodyBegin(null, h.notNull(x)());
+        flow.for_updaterBegin();
+        flow.for_end();
+      });
     });
 
     test('for_updaterBegin() joins current and continue states', () {
@@ -209,25 +271,29 @@
       // x, y, and z.  We promote x and y in the continue path, and x and z in
       // the current path.  Inside the updater, only x should be promoted.
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      var z = h.addAssignedVar('z', 'int?');
-      var stmt = _Statement();
-      h.flow.for_conditionBegin({});
-      h.flow.for_bodyBegin(stmt, h.expr());
-      h.if_(h.expr, () {
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        var stmt = _Statement();
+        flow.for_conditionBegin({});
+        flow.for_bodyBegin(stmt, h.expr());
+        h.if_(h.expr, () {
+          h.promote(x, 'int');
+          h.promote(y, 'int');
+          flow.handleContinue(stmt);
+        });
         h.promote(x, 'int');
-        h.promote(y, 'int');
-        h.flow.handleContinue(stmt);
+        h.promote(z, 'int');
+        flow.for_updaterBegin();
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
+        flow.for_end();
       });
-      h.promote(x, 'int');
-      h.promote(z, 'int');
-      h.flow.for_updaterBegin();
-      expect(h.flow.promotedType(x).type, 'int');
-      expect(h.flow.promotedType(y), isNull);
-      expect(h.flow.promotedType(z), isNull);
-      h.flow.for_end();
-      h.flow.finish();
     });
 
     test('for_end() joins break and condition-false states', () {
@@ -235,169 +301,85 @@
       // x, y, and z.  We promote x and y in the break path, and x and z in the
       // condition-false path.  After the loop, only x should be promoted.
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      var z = h.addAssignedVar('z', 'int?');
-      var stmt = _Statement();
-      h.flow.for_conditionBegin({});
-      h.flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
-      h.if_(h.expr, () {
-        h.promote(x, 'int');
-        h.promote(y, 'int');
-        h.flow.handleBreak(stmt);
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        var stmt = _Statement();
+        flow.for_conditionBegin({});
+        flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+        h.if_(h.expr, () {
+          h.promote(x, 'int');
+          h.promote(y, 'int');
+          flow.handleBreak(stmt);
+        });
+        flow.for_updaterBegin();
+        flow.for_end();
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
       });
-      h.flow.for_updaterBegin();
-      h.flow.for_end();
-      expect(h.flow.promotedType(x).type, 'int');
-      expect(h.flow.promotedType(y), isNull);
-      expect(h.flow.promotedType(z), isNull);
-      h.flow.finish();
     });
 
     test('forEach_bodyBegin() un-promotes', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.promote(x, 'int');
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.forEach_bodyBegin({x});
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.forEach_end();
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.forEach_bodyBegin({x});
+        expect(flow.promotedType(x), isNull);
+        flow.forEach_end();
+      });
     });
 
     test('forEach_end() restores state before loop', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.forEach_bodyBegin({});
-      h.promote(x, 'int');
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.forEach_end();
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.forEach_bodyBegin({});
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.forEach_end();
+        expect(flow.promotedType(x), isNull);
+      });
     });
 
     test('ifStatement_end(false) keeps else branch if then branch exits', () {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.ifStatement_thenBegin(h.eqNull(x)());
-      h.flow.handleExit();
-      h.flow.ifStatement_end(false);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp_rightBegin(isAnd: true) promotes in RHS', () {
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.logicalBinaryOp_rightBegin(h.notNull(x)(), isAnd: true);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: true);
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp_rightEnd(isAnd: true) keeps promotions from RHS', () {
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: true);
-      var wholeExpr = _Expression();
-      h.flow.logicalBinaryOp_end(wholeExpr, h.notNull(x)(), isAnd: true);
-      h.flow.ifStatement_thenBegin(wholeExpr);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.ifStatement_end(false);
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp_rightEnd(isAnd: false) keeps promotions from RHS',
-        () {
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: false);
-      var wholeExpr = _Expression();
-      h.flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x)(), isAnd: false);
-      h.flow.ifStatement_thenBegin(wholeExpr);
-      h.flow.ifStatement_elseBegin();
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.ifStatement_end(true);
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp_rightBegin(isAnd: false) promotes in RHS', () {
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      h.flow.logicalBinaryOp_rightBegin(h.eqNull(x)(), isAnd: false);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: false);
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp(isAnd: true) joins promotions', () {
-      // if (x != null && y != null) {
-      //   promotes x and y
-      // }
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      h.if_(h.and(h.notNull(x), h.notNull(y)), () {
-        expect(h.flow.promotedType(x).type, 'int');
-        expect(h.flow.promotedType(y).type, 'int');
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.ifStatement_thenBegin(h.eqNull(x)());
+        flow.handleExit();
+        flow.ifStatement_end(false);
+        expect(flow.promotedType(x).type, 'int');
       });
-      h.flow.finish();
-    });
-
-    test('logicalBinaryOp(isAnd: false) joins promotions', () {
-      // if (x == null || y == null) {} else {
-      //   promotes x and y
-      // }
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var y = h.addAssignedVar('y', 'int?');
-      h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
-        expect(h.flow.promotedType(x).type, 'int');
-        expect(h.flow.promotedType(y).type, 'int');
-      });
-      h.flow.finish();
-    });
-
-    test('Infinite loop does not implicitly assign variables', () {
-      var h = _Harness();
-      var x = h.addUnassignedVar('x', 'int');
-      var trueCondition = _Expression();
-      h.flow.whileStatement_conditionBegin({x});
-      h.flow.booleanLiteral(trueCondition, true);
-      h.flow.whileStatement_bodyBegin(_Statement(), trueCondition);
-      h.flow.whileStatement_end();
-      expect(h.flow.isAssigned(x), false);
-    });
-
-    test('If(false) does not discard promotions', () {
-      var h = _Harness();
-      var x = h.addAssignedVar('x', 'Object');
-      h.promote(x, 'int');
-      expect(h.flow.promotedType(x).type, 'int');
-      // if (false) {
-      var falseExpression = _Expression();
-      h.flow.booleanLiteral(falseExpression, false);
-      h.flow.ifStatement_thenBegin(falseExpression);
-      expect(h.flow.promotedType(x).type, 'int');
-      h.flow.ifStatement_end(false);
     });
 
     void _checkIs(String declaredType, String tryPromoteType,
         String expectedPromotedType) {
       var h = _Harness();
-      var x = h.addAssignedVar('x', 'int?');
-      var expr = _Expression();
-      h.flow.isExpression_end(expr, x, false, _Type(tryPromoteType));
-      h.flow.ifStatement_thenBegin(expr);
-      if (expectedPromotedType == null) {
-        expect(h.flow.promotedType(x), isNull);
-      } else {
-        expect(h.flow.promotedType(x).type, expectedPromotedType);
-      }
-      h.flow.ifStatement_elseBegin();
-      expect(h.flow.promotedType(x), isNull);
-      h.flow.ifStatement_end(true);
-      h.flow.finish();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var expr = _Expression();
+        flow.isExpression_end(expr, x, false, _Type(tryPromoteType));
+        flow.ifStatement_thenBegin(expr);
+        if (expectedPromotedType == null) {
+          expect(flow.promotedType(x), isNull);
+        } else {
+          expect(flow.promotedType(x).type, expectedPromotedType);
+        }
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_end(true);
+      });
     }
 
     test('isExpression_end promotes to a subtype', () {
@@ -411,10 +393,527 @@
     test('isExpression_end does not promote to an unrelated type', () {
       _checkIs('int', 'String', null);
     });
+
+    test('logicalBinaryOp_rightBegin(isAnd: true) promotes in RHS', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.logicalBinaryOp_rightBegin(h.notNull(x)(), isAnd: true);
+        expect(flow.promotedType(x).type, 'int');
+        flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: true);
+      });
+    });
+
+    test('logicalBinaryOp_rightEnd(isAnd: true) keeps promotions from RHS', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: true);
+        var wholeExpr = _Expression();
+        flow.logicalBinaryOp_end(wholeExpr, h.notNull(x)(), isAnd: true);
+        flow.ifStatement_thenBegin(wholeExpr);
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_end(false);
+      });
+    });
+
+    test('logicalBinaryOp_rightEnd(isAnd: false) keeps promotions from RHS',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: false);
+        var wholeExpr = _Expression();
+        flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x)(), isAnd: false);
+        flow.ifStatement_thenBegin(wholeExpr);
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('logicalBinaryOp_rightBegin(isAnd: false) promotes in RHS', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.logicalBinaryOp_rightBegin(h.eqNull(x)(), isAnd: false);
+        expect(flow.promotedType(x).type, 'int');
+        flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: false);
+      });
+    });
+
+    test('logicalBinaryOp(isAnd: true) joins promotions', () {
+      // if (x != null && y != null) {
+      //   promotes x and y
+      // }
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.if_(h.and(h.notNull(x), h.notNull(y)), () {
+          expect(flow.promotedType(x).type, 'int');
+          expect(flow.promotedType(y).type, 'int');
+        });
+      });
+    });
+
+    test('logicalBinaryOp(isAnd: false) joins promotions', () {
+      // if (x == null || y == null) {} else {
+      //   promotes x and y
+      // }
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
+          expect(flow.promotedType(x).type, 'int');
+          expect(flow.promotedType(y).type, 'int');
+        });
+      });
+    });
+
+    test('promotedType handles not-yet-seen variables', () {
+      // Note: this is needed for error recovery in the analyzer.
+      var h = _Harness();
+      var x = h.addVar('x', 'int');
+      h.run((flow) {
+        expect(flow.promotedType(x), isNull);
+        h.declare(x, initialized: true);
+      });
+    });
+
+    test('switchStatement_beginCase(false) restores previous promotions', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        flow.switchStatement_expressionEnd(_Statement());
+        flow.switchStatement_beginCase(false, {x});
+        expect(flow.promotedType(x).type, 'int');
+        flow.write(x);
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_beginCase(false, {x});
+        expect(flow.promotedType(x).type, 'int');
+        flow.write(x);
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_end(false);
+      });
+    });
+
+    test('switchStatement_beginCase(false) does not un-promote', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        flow.switchStatement_expressionEnd(_Statement());
+        flow.switchStatement_beginCase(false, {x});
+        expect(flow.promotedType(x).type, 'int');
+        flow.write(x);
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_end(false);
+      });
+    });
+
+    test('switchStatement_beginCase(true) un-promotes', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        flow.switchStatement_expressionEnd(_Statement());
+        flow.switchStatement_beginCase(true, {x});
+        expect(flow.promotedType(x), isNull);
+        flow.write(x);
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_end(false);
+      });
+    });
+
+    test('switchStatement_end(false) joins break and default', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        h.promote(y, 'int');
+        h.promote(z, 'int');
+        var stmt = _Statement();
+        flow.switchStatement_expressionEnd(stmt);
+        flow.switchStatement_beginCase(false, {y});
+        h.promote(x, 'int');
+        flow.write(y);
+        flow.handleBreak(stmt);
+        flow.switchStatement_end(false);
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z).type, 'int');
+      });
+    });
+
+    test('switchStatement_end(true) joins breaks', () {
+      var h = _Harness();
+      var w = h.addVar('w', 'int?');
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(w, initialized: true);
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        h.promote(z, 'int');
+        var stmt = _Statement();
+        flow.switchStatement_expressionEnd(stmt);
+        flow.switchStatement_beginCase(false, {x, y});
+        h.promote(w, 'int');
+        h.promote(y, 'int');
+        flow.write(x);
+        flow.handleBreak(stmt);
+        flow.switchStatement_beginCase(false, {x, y});
+        h.promote(w, 'int');
+        h.promote(x, 'int');
+        flow.write(y);
+        flow.handleBreak(stmt);
+        flow.switchStatement_end(true);
+        expect(flow.promotedType(w).type, 'int');
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z).type, 'int');
+      });
+    });
+
+    test('switchStatement_end(true) allows fall-through of last case', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var stmt = _Statement();
+        flow.switchStatement_expressionEnd(stmt);
+        flow.switchStatement_beginCase(false, {});
+        h.promote(x, 'int');
+        flow.handleBreak(stmt);
+        flow.switchStatement_beginCase(false, {});
+        flow.switchStatement_end(true);
+        expect(flow.promotedType(x), isNull);
+      });
+    });
+
+    test('tryCatchStatement_bodyEnd() restores pre-try state', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.tryCatchStatement_bodyBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_catchBegin();
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+      });
+    });
+
+    test('tryCatchStatement_bodyEnd() un-promotes variables assigned in body',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryCatchStatement_bodyBegin();
+        flow.write(x);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryCatchStatement_bodyEnd({x});
+        flow.tryCatchStatement_catchBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+      });
+    });
+
+    test('tryCatchStatement_catchBegin() restores previous post-body state',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.tryCatchStatement_bodyBegin();
+        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_catchBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_catchBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+      });
+    });
+
+    test('tryCatchStatement_catchEnd() joins catch state with after-try state',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        flow.tryCatchStatement_bodyBegin();
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_catchBegin();
+        h.promote(x, 'int');
+        h.promote(z, 'int');
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+        // Only x should be promoted, because it's the only variable promoted
+        // in both the try body and the catch handler.
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
+      });
+    });
+
+    test('tryCatchStatement_catchEnd() joins catch states', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        flow.tryCatchStatement_bodyBegin();
+        flow.handleExit();
+        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_catchBegin();
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_catchBegin();
+        h.promote(x, 'int');
+        h.promote(z, 'int');
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+        // Only x should be promoted, because it's the only variable promoted
+        // in both catch handlers.
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
+      });
+    });
+
+    test('tryFinallyStatement_finallyBegin() restores pre-try state', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.tryFinallyStatement_bodyBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryFinallyStatement_finallyBegin({});
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryFinallyStatement_end({});
+      });
+    });
+
+    test(
+        'tryFinallyStatement_finallyBegin() un-promotes variables assigned in '
+        'body', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryFinallyStatement_bodyBegin();
+        flow.write(x);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryFinallyStatement_finallyBegin({x});
+        expect(flow.promotedType(x), isNull);
+        flow.tryFinallyStatement_end({});
+      });
+    });
+
+    test('tryFinallyStatement_end() restores promotions from try body', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        flow.tryFinallyStatement_bodyBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryFinallyStatement_finallyBegin({});
+        expect(flow.promotedType(x), isNull);
+        h.promote(y, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryFinallyStatement_end({});
+        // Both x and y should now be promoted.
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+      });
+    });
+
+    test(
+        'tryFinallyStatement_end() does not restore try body promotions for '
+        'variables assigned in finally', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        flow.tryFinallyStatement_bodyBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryFinallyStatement_finallyBegin({});
+        expect(flow.promotedType(x), isNull);
+        flow.write(x);
+        flow.write(y);
+        h.promote(y, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.tryFinallyStatement_end({x, y});
+        // x should not be re-promoted, because it might have been assigned a
+        // non-promoted value in the "finally" block.  But y's promotion still
+        // stands, because y was promoted in the finally block.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+      });
+    });
+
+    test('whileStatement_conditionBegin() un-promotes', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.whileStatement_conditionBegin({x});
+        expect(flow.promotedType(x), isNull);
+        flow.whileStatement_bodyBegin(_Statement(), _Expression());
+        flow.whileStatement_end();
+      });
+    });
+
+    test('whileStatement_conditionBegin() handles not-yet-seen variables', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.whileStatement_conditionBegin({x});
+        flow.add(x, assigned: true);
+        flow.whileStatement_bodyBegin(_Statement(), _Expression());
+        flow.whileStatement_end();
+      });
+    });
+
+    test('whileStatement_bodyBegin() promotes', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.whileStatement_conditionBegin({});
+        flow.whileStatement_bodyBegin(_Statement(), h.notNull(x)());
+        expect(flow.promotedType(x).type, 'int');
+        flow.whileStatement_end();
+      });
+    });
+
+    test('whileStatement_end() joins break and condition-false states', () {
+      // To test that the states are properly joined, we have three variables:
+      // x, y, and z.  We promote x and y in the break path, and x and z in the
+      // condition-false path.  After the loop, only x should be promoted.
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      var z = h.addVar('z', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.declare(z, initialized: true);
+        var stmt = _Statement();
+        flow.whileStatement_conditionBegin({});
+        flow.whileStatement_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+        h.if_(h.expr, () {
+          h.promote(x, 'int');
+          h.promote(y, 'int');
+          flow.handleBreak(stmt);
+        });
+        flow.whileStatement_end();
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y), isNull);
+        expect(flow.promotedType(z), isNull);
+      });
+    });
+
+    test('Infinite loop does not implicitly assign variables', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int');
+      h.run((flow) {
+        h.declare(x, initialized: false);
+        var trueCondition = _Expression();
+        flow.whileStatement_conditionBegin({x});
+        flow.booleanLiteral(trueCondition, true);
+        flow.whileStatement_bodyBegin(_Statement(), trueCondition);
+        flow.whileStatement_end();
+        expect(flow.isAssigned(x), false);
+      });
+    });
+
+    test('If(false) does not discard promotions', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'Object');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        // if (false) {
+        var falseExpression = _Expression();
+        flow.booleanLiteral(falseExpression, false);
+        flow.ifStatement_thenBegin(falseExpression);
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_end(false);
+      });
+    });
   });
 
   group('State', () {
-    var emptySet = FlowModel<_Var, _Type>(true).notAssigned;
     var intVar = _Var('x', _Type('int'));
     var intQVar = _Var('x', _Type('int?'));
     var objectQVar = _Var('x', _Type('Object?'));
@@ -431,8 +930,7 @@
           var s = initial.setReachable(newReachability);
           expect(s, isNot(same(initial)));
           expect(s.reachable, newReachability);
-          expect(s.notAssigned, same(initial.notAssigned));
-          expect(s.promoted, same(initial.promoted));
+          expect(s.variableInfo, same(initial.variableInfo));
         }
 
         _check(unreachable, true);
@@ -445,24 +943,21 @@
         // By default, added variables are considered unassigned.
         var s1 = FlowModel<_Var, _Type>(true);
         var s2 = s1.add(intVar);
-        expect(s2.notAssigned.contains(intVar), true);
         expect(s2.reachable, true);
-        expect(s2.promoted, {intVar: null});
+        expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, false)});
       });
 
       test('unassigned', () {
         var s1 = FlowModel<_Var, _Type>(true);
         var s2 = s1.add(intVar, assigned: false);
-        expect(s2.notAssigned.contains(intVar), true);
         expect(s2.reachable, true);
-        expect(s2.promoted, {intVar: null});
+        expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, false)});
       });
 
       test('assigned', () {
         var s1 = FlowModel<_Var, _Type>(true);
         var s2 = s1.add(intVar, assigned: true);
-        expect(s2.notAssigned.contains(intVar), false);
-        expect(s2.promoted, {intVar: null});
+        expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, true)});
       });
     });
 
@@ -493,9 +988,9 @@
         var s1 = FlowModel<_Var, _Type>(true).add(intQVar);
         var s2 = s1.promote(h, intQVar, _Type('int'));
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
         _Type.allowComparisons(() {
-          expect(s2.promoted, {intQVar: _Type('int')});
+          expect(s2.variableInfo,
+              {intQVar: VariableModel<_Type>(_Type('int'), false)});
         });
       });
 
@@ -533,9 +1028,9 @@
             .promote(h, objectQVar, _Type('int?'));
         var s2 = s1.promote(h, objectQVar, _Type('int'));
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
         _Type.allowComparisons(() {
-          expect(s2.promoted, {objectQVar: _Type('int')});
+          expect(s2.variableInfo,
+              {objectQVar: VariableModel<_Type>(_Type('int'), false)});
         });
       });
     });
@@ -545,17 +1040,16 @@
       test('unchanged', () {
         var h = _Harness();
         var s1 = FlowModel<_Var, _Type>(true).add(objectQVar, assigned: true);
-        var s2 = s1.write(h, emptySet, objectQVar);
+        var s2 = s1.write(h, objectQVar);
         expect(s2, same(s1));
       });
 
       test('marks as assigned', () {
         var h = _Harness();
         var s1 = FlowModel<_Var, _Type>(true).add(objectQVar, assigned: false);
-        var s2 = s1.write(h, emptySet, objectQVar);
+        var s2 = s1.write(h, objectQVar);
         expect(s2.reachable, true);
-        expect(s2.notAssigned.contains(objectQVar), false);
-        expect(s2.promoted, same(s1.promoted));
+        expect(s2.variableInfo[objectQVar], VariableModel<_Type>(null, true));
       });
 
       test('un-promotes', () {
@@ -563,11 +1057,10 @@
         var s1 = FlowModel<_Var, _Type>(true)
             .add(objectQVar, assigned: true)
             .promote(h, objectQVar, _Type('int'));
-        expect(s1.promoted, contains(objectQVar));
-        var s2 = s1.write(h, emptySet, objectQVar);
+        expect(s1.variableInfo, contains(objectQVar));
+        var s2 = s1.write(h, objectQVar);
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
-        expect(s2.promoted, {objectQVar: null});
+        expect(s2.variableInfo, {objectQVar: VariableModel<_Type>(null, true)});
       });
     });
 
@@ -584,8 +1077,9 @@
         var s1 = FlowModel<_Var, _Type>(true).add(intQVar);
         var s2 = s1.markNonNullable(h, intQVar);
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
-        expect(s2.promoted[intQVar].type, 'int');
+        _Type.allowComparisons(() {
+          expect(s2.variableInfo[intQVar], VariableModel(_Type('int'), false));
+        });
       });
 
       test('promoted -> unchanged', () {
@@ -604,9 +1098,9 @@
             .promote(h, objectQVar, _Type('int?'));
         var s2 = s1.markNonNullable(h, objectQVar);
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
         _Type.allowComparisons(() {
-          expect(s2.promoted, {objectQVar: _Type('int')});
+          expect(s2.variableInfo,
+              {objectQVar: VariableModel<_Type>(_Type('int'), false)});
         });
       });
     });
@@ -618,7 +1112,7 @@
             .add(objectQVar)
             .add(intQVar)
             .promote(h, objectQVar, _Type('int'));
-        var s2 = s1.removePromotedAll([intQVar].toSet());
+        var s2 = s1.removePromotedAll([intQVar], null);
         expect(s2, same(s1));
       });
 
@@ -629,11 +1123,13 @@
             .add(intQVar)
             .promote(h, objectQVar, _Type('int'))
             .promote(h, intQVar, _Type('int'));
-        var s2 = s1.removePromotedAll([intQVar].toSet());
+        var s2 = s1.removePromotedAll([intQVar], null);
         expect(s2.reachable, true);
-        expect(s2.notAssigned, same(s1.notAssigned));
         _Type.allowComparisons(() {
-          expect(s2.promoted, {objectQVar: _Type('int'), intQVar: null});
+          expect(s2.variableInfo, {
+            objectQVar: VariableModel<_Type>(_Type('int'), false),
+            intQVar: VariableModel<_Type>(null, false)
+          });
         });
       });
     });
@@ -643,14 +1139,10 @@
         var h = _Harness();
         var reachable = FlowModel<_Var, _Type>(true);
         var unreachable = reachable.setReachable(false);
-        expect(
-            reachable.restrict(h, emptySet, reachable, Set()), same(reachable));
-        expect(reachable.restrict(h, emptySet, unreachable, Set()),
-            same(unreachable));
-        expect(unreachable.restrict(h, emptySet, unreachable, Set()),
-            same(unreachable));
-        expect(unreachable.restrict(h, emptySet, unreachable, Set()),
-            same(unreachable));
+        expect(reachable.restrict(h, reachable, Set()), same(reachable));
+        expect(reachable.restrict(h, unreachable, Set()), same(unreachable));
+        expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
+        expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
       });
 
       test('assignments', () {
@@ -660,13 +1152,13 @@
         var c = _Var('c', _Type('int'));
         var d = _Var('d', _Type('int'));
         var s0 = FlowModel<_Var, _Type>(true).add(a).add(b).add(c).add(d);
-        var s1 = s0.write(h, emptySet, a).write(h, emptySet, b);
-        var s2 = s0.write(h, emptySet, a).write(h, emptySet, c);
-        var result = s1.restrict(h, emptySet, s2, Set());
-        expect(result.notAssigned.contains(a), false);
-        expect(result.notAssigned.contains(b), false);
-        expect(result.notAssigned.contains(c), false);
-        expect(result.notAssigned.contains(d), true);
+        var s1 = s0.write(h, a).write(h, b);
+        var s2 = s0.write(h, a).write(h, c);
+        var result = s1.restrict(h, s2, Set());
+        expect(result.variableInfo[a].assigned, true);
+        expect(result.variableInfo[b].assigned, true);
+        expect(result.variableInfo[c].assigned, true);
+        expect(result.variableInfo[d].assigned, false);
       });
 
       test('promotion', () {
@@ -677,13 +1169,12 @@
           var s0 = FlowModel<_Var, _Type>(true).add(x, assigned: true);
           var s1 = thisType == null ? s0 : s0.promote(h, x, _Type(thisType));
           var s2 = otherType == null ? s0 : s0.promote(h, x, _Type(otherType));
-          var result =
-              s1.restrict(h, emptySet, s2, unsafe ? [x].toSet() : Set());
+          var result = s1.restrict(h, s2, unsafe ? [x].toSet() : Set());
           if (expectedType == null) {
-            expect(result.promoted, contains(x));
-            expect(result.promoted[x], isNull);
+            expect(result.variableInfo, contains(x));
+            expect(result.variableInfo[x].promotedType, isNull);
           } else {
-            expect(result.promoted[x].type, expectedType);
+            expect(result.variableInfo[x].promotedType.type, expectedType);
           }
         }
 
@@ -706,77 +1197,97 @@
         var x = _Var('x', _Type('Object?'));
         var s0 = FlowModel<_Var, _Type>(true);
         var s1 = s0.add(x, assigned: true);
-        expect(s0.restrict(h, emptySet, s1, {}), same(s0));
-        expect(s0.restrict(h, emptySet, s1, {x}), same(s0));
-        expect(s1.restrict(h, emptySet, s0, {}), same(s1));
-        expect(s1.restrict(h, emptySet, s0, {x}), same(s1));
+        expect(s0.restrict(h, s1, {}), same(s0));
+        expect(s0.restrict(h, s1, {x}), same(s0));
+        expect(s1.restrict(h, s0, {}), same(s1));
+        expect(s1.restrict(h, s0, {x}), same(s1));
       });
     });
   });
 
   group('join', () {
-    group('should re-use an input if possible', () {
-      var x = _Var('x', null);
-      var y = _Var('y', null);
-      var intType = _Type('int');
-      var intQType = _Type('int?');
-      var stringType = _Type('String');
-      const emptyMap = <Null, Null>{};
+    var x = _Var('x', null);
+    var y = _Var('y', null);
+    var intType = _Type('int');
+    var intQType = _Type('int?');
+    var stringType = _Type('String');
+    const emptyMap = <Null, VariableModel<Null>>{};
 
+    VariableModel<_Type> model(_Type type) => VariableModel<_Type>(type, true);
+
+    group('without input reuse', () {
+      test('promoted with unpromoted', () {
+        var h = _Harness();
+        var p1 = {x: model(intType), y: model(null)};
+        var p2 = {x: model(null), y: model(intType)};
+        expect(FlowModel.joinVariableInfo(h, p1, p2),
+            {x: model(null), y: model(null)});
+      });
+    });
+    group('should re-use an input if possible', () {
       test('identical inputs', () {
         var h = _Harness();
-        var p = {x: intType, y: stringType};
-        expect(FlowModel.joinPromoted(h, p, p), same(p));
+        var p = {x: model(intType), y: model(stringType)};
+        expect(FlowModel.joinVariableInfo(h, p, p), same(p));
       });
 
       test('one input empty', () {
         var h = _Harness();
-        var p1 = {x: intType, y: stringType};
-        var p2 = <_Var, _Type>{};
-        expect(FlowModel.joinPromoted(h, p1, p2), same(emptyMap));
-        expect(FlowModel.joinPromoted(h, p2, p1), same(emptyMap));
+        var p1 = {x: model(intType), y: model(stringType)};
+        var p2 = <_Var, VariableModel<_Type>>{};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), same(emptyMap));
+        expect(FlowModel.joinVariableInfo(h, p2, p1), same(emptyMap));
+      });
+
+      test('promoted with unpromoted', () {
+        var h = _Harness();
+        var p1 = {x: model(intType)};
+        var p2 = {x: model(null)};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+        expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
       });
 
       test('related types', () {
         var h = _Harness();
-        var p1 = {x: intType};
-        var p2 = {x: intQType};
-        expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
-        expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+        var p1 = {x: model(intType)};
+        var p2 = {x: model(intQType)};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+        expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
       });
 
       test('unrelated types', () {
         var h = _Harness();
-        var p1 = {x: intType};
-        var p2 = {x: stringType};
-        expect(FlowModel.joinPromoted(h, p1, p2), {x: null});
-        expect(FlowModel.joinPromoted(h, p2, p1), {x: null});
+        var p1 = {x: model(intType)};
+        var p2 = {x: model(stringType)};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), {x: model(null)});
+        expect(FlowModel.joinVariableInfo(h, p2, p1), {x: model(null)});
       });
 
       test('sub-map', () {
         var h = _Harness();
-        var p1 = {x: intType, y: stringType};
-        var p2 = {x: intType};
-        expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
-        expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+        var xModel = model(intType);
+        var p1 = {x: xModel, y: model(stringType)};
+        var p2 = {x: xModel};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+        expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
       });
 
       test('sub-map with matched subtype', () {
         var h = _Harness();
-        var p1 = {x: intType, y: stringType};
-        var p2 = {x: intQType};
-        expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
-        expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+        var p1 = {x: model(intType), y: model(stringType)};
+        var p2 = {x: model(intQType)};
+        expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+        expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
       });
 
       test('sub-map with mismatched subtype', () {
         var h = _Harness();
-        var p1 = {x: intQType, y: stringType};
-        var p2 = {x: intType};
-        var join12 = FlowModel.joinPromoted(h, p1, p2);
-        _Type.allowComparisons(() => expect(join12, {x: intQType}));
-        var join21 = FlowModel.joinPromoted(h, p2, p1);
-        _Type.allowComparisons(() => expect(join21, {x: intQType}));
+        var p1 = {x: model(intQType), y: model(stringType)};
+        var p2 = {x: model(intType)};
+        var join12 = FlowModel.joinVariableInfo(h, p1, p2);
+        _Type.allowComparisons(() => expect(join12, {x: model(intQType)}));
+        var join21 = FlowModel.joinVariableInfo(h, p2, p1);
+        _Type.allowComparisons(() => expect(join21, {x: model(intQType)}));
       });
     });
   });
@@ -811,26 +1322,15 @@
         NodeOperations<_Expression>,
         TypeOperations<_Var, _Type>,
         FunctionBodyAccess<_Var> {
-  FlowAnalysis<_Statement, _Expression, _Var, _Type> flow;
-
-  _Harness() {
-    flow = FlowAnalysis<_Statement, _Expression, _Var, _Type>(this, this, this);
-  }
+  FlowAnalysis<_Statement, _Expression, _Var, _Type> _flow;
 
   /// Returns a [LazyExpression] representing an expression with now special
   /// flow analysis semantics.
   LazyExpression get expr => () => _Expression();
 
-  _Var addAssignedVar(String name, String type) {
-    var v = _Var(name, _Type(type));
-    flow.add(v, assigned: true);
-    return v;
-  }
-
-  _Var addUnassignedVar(String name, String type) {
-    var v = _Var(name, _Type(type));
-    flow.add(v, assigned: false);
-    return v;
+  _Var addVar(String name, String type) {
+    assert(_flow == null);
+    return _Var(name, _Type(type));
   }
 
   /// Given two [LazyExpression]s, produces a new [LazyExpression] representing
@@ -838,8 +1338,8 @@
   LazyExpression and(LazyExpression lhs, LazyExpression rhs) {
     return () {
       var expr = _Expression();
-      flow.logicalBinaryOp_rightBegin(lhs(), isAnd: true);
-      flow.logicalBinaryOp_end(expr, rhs(), isAnd: true);
+      _flow.logicalBinaryOp_rightBegin(lhs(), isAnd: true);
+      _flow.logicalBinaryOp_end(expr, rhs(), isAnd: true);
       return expr;
     };
   }
@@ -850,37 +1350,44 @@
       LazyExpression cond, LazyExpression ifTrue, LazyExpression ifFalse) {
     return () {
       var expr = _Expression();
-      flow.conditional_thenBegin(cond());
-      flow.conditional_elseBegin(ifTrue());
-      flow.conditional_end(expr, ifFalse());
+      _flow.conditional_thenBegin(cond());
+      _flow.conditional_elseBegin(ifTrue());
+      _flow.conditional_end(expr, ifFalse());
       return expr;
     };
   }
 
+  FlowAnalysis<_Statement, _Expression, _Var, _Type> createFlow() =>
+      FlowAnalysis<_Statement, _Expression, _Var, _Type>(this, this, this);
+
+  void declare(_Var v, {@required bool initialized}) {
+    _flow.add(v, assigned: initialized);
+  }
+
   /// Creates a [LazyExpression] representing an `== null` check performed on
   /// [variable].
   LazyExpression eqNull(_Var variable) {
     return () {
       var expr = _Expression();
-      flow.conditionEqNull(expr, variable, notEqual: false);
+      _flow.conditionEqNull(expr, variable, notEqual: false);
       return expr;
     };
   }
 
   /// Invokes flow analysis of an `if` statement with no `else` part.
   void if_(LazyExpression cond, void ifTrue()) {
-    flow.ifStatement_thenBegin(cond());
+    _flow.ifStatement_thenBegin(cond());
     ifTrue();
-    flow.ifStatement_end(false);
+    _flow.ifStatement_end(false);
   }
 
   /// Invokes flow analysis of an `if` statement with an `else` part.
   void ifElse(LazyExpression cond, void ifTrue(), void ifFalse()) {
-    flow.ifStatement_thenBegin(cond());
+    _flow.ifStatement_thenBegin(cond());
     ifTrue();
-    flow.ifStatement_elseBegin();
+    _flow.ifStatement_elseBegin();
     ifFalse();
-    flow.ifStatement_end(false);
+    _flow.ifStatement_end(false);
   }
 
   @override
@@ -894,7 +1401,7 @@
   LazyExpression isNotType(_Var variable, String type) {
     return () {
       var expr = _Expression();
-      flow.isExpression_end(expr, variable, true, _Type(type));
+      _flow.isExpression_end(expr, variable, true, _Type(type));
       return expr;
     };
   }
@@ -940,7 +1447,7 @@
   LazyExpression notNull(_Var variable) {
     return () {
       var expr = _Expression();
-      flow.conditionEqNull(expr, variable, notEqual: true);
+      _flow.conditionEqNull(expr, variable, notEqual: true);
       return expr;
     };
   }
@@ -950,15 +1457,15 @@
   LazyExpression or(LazyExpression lhs, LazyExpression rhs) {
     return () {
       var expr = _Expression();
-      flow.logicalBinaryOp_rightBegin(lhs(), isAnd: false);
-      flow.logicalBinaryOp_end(expr, rhs(), isAnd: false);
+      _flow.logicalBinaryOp_rightBegin(lhs(), isAnd: false);
+      _flow.logicalBinaryOp_end(expr, rhs(), isAnd: false);
       return expr;
     };
   }
 
   /// Causes [variable] to be promoted to [type].
   void promote(_Var variable, String type) {
-    if_(isNotType(variable, type), flow.handleExit);
+    if_(isNotType(variable, type), _flow.handleExit);
   }
 
   @override
@@ -970,6 +1477,14 @@
     }
   }
 
+  void run(
+      void callback(FlowAnalysis<_Statement, _Expression, _Var, _Type> flow)) {
+    assert(_flow == null);
+    _flow = createFlow();
+    callback(_flow);
+    _flow.finish();
+  }
+
   @override
   _Expression unwrapParenthesized(_Expression node) {
     // TODO(paulberry): test cases where this matters
diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart
index f130cba..30206f6 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -97,7 +97,9 @@
     VariableDeclaration variable = new VariableDeclaration(null);
 
     BodyBuilder helper = new BodyBuilder(
-        library: libraryBuilder, isDeclarationInstanceMember: false, uri: uri);
+        libraryBuilder: libraryBuilder,
+        isDeclarationInstanceMember: false,
+        uri: uri);
 
     Generator generator = new ThisAccessGenerator(helper, token, false, false);
 
diff --git a/pkg/front_end/test/fasta/incremental_hello_test.dart b/pkg/front_end/test/fasta/incremental_hello_test.dart
index 06004bc..ccafee3 100644
--- a/pkg/front_end/test/fasta/incremental_hello_test.dart
+++ b/pkg/front_end/test/fasta/incremental_hello_test.dart
@@ -47,7 +47,7 @@
   } else {
     optionBuilder.sdkSummary =
         computePlatformBinariesLocation(forceBuildDir: true)
-            .resolve("vm_platform.dill");
+            .resolve("vm_platform_strong.dill");
   }
 
   final Uri helloDart =
diff --git a/pkg/front_end/test/fasta/incremental_test.dart b/pkg/front_end/test/fasta/incremental_test.dart
index 4208d17..59c2e1d 100644
--- a/pkg/front_end/test/fasta/incremental_test.dart
+++ b/pkg/front_end/test/fasta/incremental_test.dart
@@ -209,12 +209,12 @@
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
   /// The custom URI used to locate the dill file in the MemoryFileSystem.
-  final Uri sdkSummary = base.resolve("vm_platform.dill");
+  final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
 
   /// The actual location of the dill file.
   final Uri sdkSummaryFile =
       computePlatformBinariesLocation(forceBuildDir: true)
-          .resolve("vm_platform.dill");
+          .resolve("vm_platform_strong.dill");
 
   final MemoryFileSystem fs = new MemoryFileSystem(base);
 
@@ -246,4 +246,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/messages_test.dart b/pkg/front_end/test/fasta/messages_test.dart
index e2f30c9..08e960e 100644
--- a/pkg/front_end/test/fasta/messages_test.dart
+++ b/pkg/front_end/test/fasta/messages_test.dart
@@ -663,4 +663,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/outline_test.dart b/pkg/front_end/test/fasta/outline_test.dart
index 43e9cc9..cc5ec1d 100644
--- a/pkg/front_end/test/fasta/outline_test.dart
+++ b/pkg/front_end/test/fasta/outline_test.dart
@@ -14,4 +14,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/parser/parser_suite.dart b/pkg/front_end/test/fasta/parser/parser_suite.dart
index ad15a8f..e2321af 100644
--- a/pkg/front_end/test/fasta/parser/parser_suite.dart
+++ b/pkg/front_end/test/fasta/parser/parser_suite.dart
@@ -2,11 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
-import 'package:testing/testing.dart';
+import 'package:front_end/src/fasta/parser.dart' show ParserError, parse;
 
-import 'package:front_end/src/fasta/testing/scanner_chain.dart';
+import 'package:testing/testing.dart'
+    show Chain, ChainContext, Future, Result, Step, runMe;
 
-import 'package:front_end/src/fasta/parser.dart';
+import '../../utils/scanner_chain.dart' show Read, Scan, ScannedFile;
 
 Future<ChainContext> createContext(
     Chain suite, Map<String, String> environment) async {
@@ -40,4 +41,4 @@
 }
 
 main(List<String> arguments) =>
-    runMe(arguments, createContext, "../../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../../testing.json");
diff --git a/pkg/front_end/test/fasta/scanner/scanner_suite.dart b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
index 8ca4f7a..1fb6f442 100644
--- a/pkg/front_end/test/fasta/scanner/scanner_suite.dart
+++ b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
@@ -2,9 +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.md file.
 
-import 'package:testing/testing.dart';
+import 'package:testing/testing.dart'
+    show Chain, ChainContext, Future, Step, runMe;
 
-import 'package:front_end/src/fasta/testing/scanner_chain.dart';
+import '../../utils/scanner_chain.dart' show Read, Scan;
 
 Future<ChainContext> createContext(
     Chain suite, Map<String, String> environment) async {
@@ -19,4 +20,4 @@
 }
 
 main(List<String> arguments) =>
-    runMe(arguments, createContext, "../../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../../testing.json");
diff --git a/pkg/front_end/test/fasta/strong1_test.dart b/pkg/front_end/test/fasta/strong1_test.dart
new file mode 100644
index 0000000..cb30b7e
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong1_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+  internalMain(arguments: arguments, shards: shardCount, shard: 0);
+}
diff --git a/pkg/front_end/test/fasta/strong2_test.dart b/pkg/front_end/test/fasta/strong2_test.dart
new file mode 100644
index 0000000..10fafaf
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong2_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+  internalMain(arguments: arguments, shards: shardCount, shard: 1);
+}
diff --git a/pkg/front_end/test/fasta/strong3_test.dart b/pkg/front_end/test/fasta/strong3_test.dart
new file mode 100644
index 0000000..044c7e8
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong3_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+  internalMain(arguments: arguments, shards: shardCount, shard: 2);
+}
diff --git a/pkg/front_end/test/fasta/strong4_test.dart b/pkg/front_end/test/fasta/strong4_test.dart
new file mode 100644
index 0000000..9e459e3
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong4_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+  internalMain(arguments: arguments, shards: shardCount, shard: 3);
+}
diff --git a/pkg/front_end/test/fasta/strong_test.dart b/pkg/front_end/test/fasta/strong_test.dart
deleted file mode 100644
index e8e430d..0000000
--- a/pkg/front_end/test/fasta/strong_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE.md file.
-
-library fasta.test.strong_test;
-
-import 'dart:async' show Future;
-
-import 'testing/suite.dart';
-
-Future<FastaContext> createContext(
-    Chain suite, Map<String, String> environment) {
-  environment[ENABLE_FULL_COMPILE] = "";
-  return FastaContext.create(suite, environment);
-}
-
-main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
diff --git a/pkg/front_end/test/fasta/strong_tester.dart b/pkg/front_end/test/fasta/strong_tester.dart
new file mode 100644
index 0000000..402ff57
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong_tester.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+library fasta.test.strong_test;
+
+import 'dart:async' show Future;
+import 'dart:io' show Platform;
+
+import 'testing/suite.dart';
+
+const int shardCount = 4;
+
+Future<FastaContext> createContext(
+    Chain suite, Map<String, String> environment) {
+  environment[ENABLE_FULL_COMPILE] = "";
+  return FastaContext.create(suite, environment);
+}
+
+main(List<String> arguments) {
+  internalMain(arguments: arguments);
+}
+
+internalMain(
+    {List<String> arguments = const [], int shards = 1, int shard = 0}) {
+  runMe(arguments, createContext,
+      configurationPath: "../../testing.json",
+      me: Platform.script.resolve('strong_tester.dart'),
+      shards: shards,
+      shard: shard);
+}
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 420ed92..4170490 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -10,31 +10,12 @@
 
 import 'dart:io' show Directory, File, Platform;
 
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:kernel/ast.dart'
-    show AwaitExpression, Component, Library, Node, Visitor;
-
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-
-import 'package:kernel/core_types.dart' show CoreTypes;
-
-import 'package:kernel/kernel.dart' show loadComponentFromBytes;
-
-import 'package:kernel/target/targets.dart'
-    show TargetFlags, DiagnosticReporter;
-
-import 'package:testing/testing.dart'
+import 'package:front_end/src/api_prototype/compiler_options.dart'
     show
-        Chain,
-        ChainContext,
-        Expectation,
-        ExpectationSet,
-        Result,
-        Step,
-        TestDescription,
-        StdioProcess;
-
-import 'package:vm/target/vm.dart' show VmTarget;
+        CompilerOptions,
+        DiagnosticMessage,
+        parseExperimentalArguments,
+        parseExperimentalFlags;
 
 import 'package:front_end/src/api_prototype/compiler_options.dart'
     show CompilerOptions, DiagnosticMessage;
@@ -67,7 +48,36 @@
 import 'package:front_end/src/fasta/kernel/kernel_target.dart'
     show KernelTarget;
 
-import 'package:front_end/src/fasta/testing/kernel_chain.dart'
+import 'package:front_end/src/fasta/ticker.dart' show Ticker;
+
+import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
+
+import 'package:kernel/ast.dart'
+    show AwaitExpression, Component, Library, Node, Visitor;
+
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+
+import 'package:kernel/core_types.dart' show CoreTypes;
+
+import 'package:kernel/kernel.dart' show loadComponentFromBytes;
+
+import 'package:kernel/target/targets.dart'
+    show TargetFlags, DiagnosticReporter;
+
+import 'package:testing/testing.dart'
+    show
+        Chain,
+        ChainContext,
+        Expectation,
+        ExpectationSet,
+        Result,
+        Step,
+        TestDescription,
+        StdioProcess;
+
+import 'package:vm/target/vm.dart' show VmTarget;
+
+import '../../utils/kernel_chain.dart'
     show
         KernelTextSerialization,
         MatchContext,
@@ -77,13 +87,9 @@
         Verify,
         WriteDill;
 
-import 'package:front_end/src/fasta/testing/validating_instrumentation.dart'
+import '../../utils/validating_instrumentation.dart'
     show ValidatingInstrumentation;
 
-import 'package:front_end/src/fasta/ticker.dart' show Ticker;
-
-import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
-
 export 'package:testing/testing.dart' show Chain, runMe;
 
 const String ENABLE_FULL_COMPILE = " full compile ";
diff --git a/pkg/front_end/test/fasta/text_serialization_test.dart b/pkg/front_end/test/fasta/text_serialization_test.dart
index 07ecb85..fa51b54 100644
--- a/pkg/front_end/test/fasta/text_serialization_test.dart
+++ b/pkg/front_end/test/fasta/text_serialization_test.dart
@@ -16,4 +16,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
index 8bc8c5c..471b69d 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
@@ -117,7 +117,7 @@
   }
 }
 
-class _TypeSchemaVisitor<R> extends Visitor<R> implements TypeSchemaVisitor<R> {
+class _TypeSchemaVisitor<R> extends Visitor<R> {
   final _UnaryFunction<DartType, R> _defaultDartType;
   final _UnaryFunction<UnknownType, R> _visitUnknownType;
 
@@ -129,19 +129,12 @@
 
   @override
   R defaultDartType(DartType node) {
-    if (_defaultDartType != null) {
+    if (node is UnknownType && _visitUnknownType != null) {
+      return _visitUnknownType(node);
+    } else if (_defaultDartType != null) {
       return _defaultDartType(node);
     } else {
       return super.defaultDartType(node);
     }
   }
-
-  @override
-  R visitUnknownType(UnknownType node) {
-    if (_visitUnknownType != null) {
-      return _visitUnknownType(node);
-    } else {
-      return defaultDartType(node);
-    }
-  }
 }
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 ebc39e7..398f5a1 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
@@ -26,15 +26,14 @@
         TypePromotionState,
         UnspecifiedDeclaration;
 
-import 'package:front_end/src/fasta/testing/kernel_chain.dart'
-    show MatchContext;
-
-import 'package:front_end/src/fasta/testing/scanner_chain.dart'
-    show Read, Scan, ScannedFile;
-
 import 'package:kernel/ast.dart' show Source;
 
-import 'package:testing/testing.dart';
+import 'package:testing/testing.dart'
+    show Chain, ChainContext, ExpectationSet, Future, Result, Step, runMe;
+
+import '../utils/kernel_chain.dart' show MatchContext;
+
+import '../utils/scanner_chain.dart' show Read, Scan, ScannedFile;
 
 const String EXPECTATIONS = '''
 [
@@ -228,4 +227,4 @@
 }
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../../testing.json");
+    runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
index 56053fa..80393e4 100644
--- a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
+++ b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
@@ -69,7 +69,7 @@
   Longest path to Object: 3
   superclasses:
     Object
-  interfaces: B<T>, A, C<U>
+  interfaces: B<T>*, A, C<U>*
   classMembers:
   classSetters:
   interfaceMembers:
@@ -79,7 +79,7 @@
   Longest path to Object: 4
   superclasses:
     Object
-  interfaces: D<int, double>, B<int>, A, C<double>
+  interfaces: D<int, double>*, B<int>*, A, C<double>*
   classMembers:
   classSetters:
   interfaceMembers:
@@ -89,7 +89,7 @@
   Longest path to Object: 4
   superclasses:
     Object
-  interfaces: D<int, bool>, B<int>, A, C<bool>
+  interfaces: D<int, bool>*, B<int>*, A, C<bool>*
   classMembers:
   classSetters:
   interfaceMembers:
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
index 128559f..4d47cf6 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -14,6 +14,7 @@
         Library,
         NamedType,
         Node,
+        Nullability,
         Supertype,
         TreeNode,
         TypeParameter,
@@ -40,6 +41,7 @@
         ParsedTypedef,
         ParsedVoidType,
         Visitor;
+import 'type_parser.dart';
 
 Component parseComponent(String source, Uri uri) {
   Uri coreUri = Uri.parse("dart:core");
@@ -90,6 +92,18 @@
 
   final KernelEnvironment parent;
 
+  /// Collects types to set their nullabilities after type parameters are ready.
+  ///
+  /// [TypeParameterType]s may receive their nullability at the declaration or
+  /// from the bound of the [TypeParameter]s they refer to.  If a
+  /// [TypeParameterType] is allocated at the time when the bound of the
+  /// [TypeParameter] is not set yet, that is, if it's encountered in that
+  /// bound or the bound of other [TypeParameter] from the same scope, and the
+  /// nullability of that [TypeParameterType] is not set at declaration, the
+  /// [TypeParameterType] is added to [pendingNullabilities], so that it can be
+  /// updated when the bound of the [TypeParameter] is ready.
+  final List<TypeParameterType> pendingNullabilities = <TypeParameterType>[];
+
   KernelEnvironment(this.uri, this.fileUri, [this.parent]);
 
   Node kernelFromParsedType(ParsedType type) {
@@ -161,14 +175,31 @@
       } else if (kernelArguments.length != typeVariables.length) {
         throw "Expected ${typeVariables.length} type arguments: $node";
       }
-      return new InterfaceType(declaration, kernelArguments, node.nullability);
+      return new InterfaceType(declaration, kernelArguments,
+          interpretParsedNullability(node.parsedNullability));
     } else if (declaration is TypeParameter) {
       if (arguments.isNotEmpty) {
         throw "Type variable can't have arguments (${node.name})";
       }
-      return new TypeParameterType(declaration, null, node.nullability);
+      Nullability nullability = declaration.bound == null
+          ? null
+          : TypeParameterType.computeNullabilityFromBound(declaration);
+      TypeParameterType type = new TypeParameterType(
+          declaration,
+          null,
+          interpretParsedNullability(node.parsedNullability,
+              ifOmitted: nullability));
+      // If the nullability was omitted on the type and can't be computed from
+      // the bound because it's not yet available, it will be set to null.  In
+      // that case, put it to the list to be updated later, when the bound is
+      // available.
+      if (type.declaredNullability == null) {
+        environment.pendingNullabilities.add(type);
+      }
+      return type;
     } else if (declaration is Typedef) {
-      return new TypedefType(declaration, kernelArguments, node.nullability);
+      return new TypedefType(declaration, kernelArguments,
+          interpretParsedNullability(node.parsedNullability));
     } else {
       throw "Unhandled ${declaration.runtimeType}";
     }
@@ -264,7 +295,7 @@
         namedParameters: namedParameters,
         requiredParameterCount: node.arguments.required.length,
         typeParameters: parameterEnvironment.parameters,
-        nullability: node.nullability);
+        nullability: interpretParsedNullability(node.parsedNullability));
   }
 
   VoidType visitVoidType(ParsedVoidType node, KernelEnvironment environment) {
@@ -322,6 +353,12 @@
     for (int i = 0; i < typeParameters.length; i++) {
       typeParameters[i].defaultType = defaultTypes[i];
     }
+
+    for (TypeParameterType type in nestedEnvironment.pendingNullabilities) {
+      type.declaredNullability =
+          TypeParameterType.computeNullabilityFromBound(type.parameter);
+    }
+    nestedEnvironment.pendingNullabilities.clear();
     return new ParameterEnvironment(typeParameters, nestedEnvironment);
   }
 }
diff --git a/pkg/front_end/test/fasta/types/type_parser.dart b/pkg/front_end/test/fasta/types/type_parser.dart
index a40bbdf..c9e0592 100644
--- a/pkg/front_end/test/fasta/types/type_parser.dart
+++ b/pkg/front_end/test/fasta/types/type_parser.dart
@@ -2,25 +2,53 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "package:kernel/ast.dart" show Nullability;
+import 'package:kernel/ast.dart' show Nullability;
 
 import "package:front_end/src/fasta/scanner.dart" show scanString, Token;
 
 import "package:front_end/src/fasta/parser/type_info_impl.dart"
     show splitCloser;
 
+import "package:front_end/src/fasta/problems.dart";
+import 'package:kernel/text/text_serialization_verifier.dart';
+
 abstract class ParsedType {
   R accept<R, A>(Visitor<R, A> visitor, [A a]);
 }
 
+enum ParsedNullability {
+  // Used when the type is declared with the '?' suffix.
+  nullable,
+
+  // Used when the type is declared with the '*' suffix.
+  legacy,
+
+  // Used when the nullability suffix is omitted after the type declaration.
+  omitted,
+}
+
+Nullability interpretParsedNullability(ParsedNullability parsedNullability,
+    {Nullability ifOmitted = Nullability.nonNullable}) {
+  switch (parsedNullability) {
+    case ParsedNullability.nullable:
+      return Nullability.nullable;
+    case ParsedNullability.legacy:
+      return Nullability.legacy;
+    case ParsedNullability.omitted:
+      return ifOmitted;
+  }
+  return unhandled(
+      "$parsedNullability", "interpretParsedNullability", noOffset, noUri);
+}
+
 class ParsedInterfaceType extends ParsedType {
   final String name;
 
   final List<ParsedType> arguments;
 
-  final Nullability nullability;
+  final ParsedNullability parsedNullability;
 
-  ParsedInterfaceType(this.name, this.arguments, this.nullability);
+  ParsedInterfaceType(this.name, this.arguments, this.parsedNullability);
 
   String toString() {
     StringBuffer sb = new StringBuffer();
@@ -120,10 +148,10 @@
 
   final ParsedArguments arguments;
 
-  final Nullability nullability;
+  final ParsedNullability parsedNullability;
 
-  ParsedFunctionType(
-      this.typeVariables, this.returnType, this.arguments, this.nullability);
+  ParsedFunctionType(this.typeVariables, this.returnType, this.arguments,
+      this.parsedNullability);
 
   String toString() {
     StringBuffer sb = new StringBuffer();
@@ -268,12 +296,12 @@
     }
   }
 
-  Nullability parseNullability() {
-    Nullability result = Nullability.nonNullable;
+  ParsedNullability parseNullability() {
+    ParsedNullability result = ParsedNullability.omitted;
     if (optionalAdvance("?")) {
-      result = Nullability.nullable;
+      result = ParsedNullability.nullable;
     } else if (optionalAdvance("*")) {
-      result = Nullability.legacy;
+      result = ParsedNullability.legacy;
     }
     return result;
   }
@@ -288,7 +316,7 @@
         type = parseFunctionType();
       } else if (optionalAdvance("void")) {
         type = new ParsedInterfaceType(
-            "void", <ParsedType>[], Nullability.nullable);
+            "void", <ParsedType>[], ParsedNullability.nullable);
         optionalAdvance("?");
       } else {
         String name = parseName();
@@ -303,8 +331,8 @@
           peek = splitCloser(peek) ?? peek;
           expect(">");
         }
-        Nullability nullability = parseNullability();
-        type = new ParsedInterfaceType(name, arguments, nullability);
+        ParsedNullability parsedNullability = parseNullability();
+        type = new ParsedInterfaceType(name, arguments, parsedNullability);
       }
       if (result == null) {
         result = type;
@@ -325,10 +353,10 @@
     ParsedArguments arguments = parseArguments();
     expect("-");
     expect(">");
-    Nullability nullability = parseNullability();
+    ParsedNullability parsedNullability = parseNullability();
     ParsedType returnType = parseReturnType();
     return new ParsedFunctionType(
-        typeVariables, returnType, arguments, nullability);
+        typeVariables, returnType, arguments, parsedNullability);
   }
 
   String parseName() {
diff --git a/pkg/front_end/test/fasta/unlinked_scope_test.dart b/pkg/front_end/test/fasta/unlinked_scope_test.dart
index 69e04e0..05a25dc 100644
--- a/pkg/front_end/test/fasta/unlinked_scope_test.dart
+++ b/pkg/front_end/test/fasta/unlinked_scope_test.dart
@@ -67,7 +67,7 @@
   MockBodyBuilder.internal(
       MockLibraryBuilder libraryBuilder, String name, Scope scope)
       : super(
-            library: libraryBuilder,
+            libraryBuilder: libraryBuilder,
             member: libraryBuilder.mockProcedure(name),
             enclosingScope: scope,
             formalParameterScope: scope,
diff --git a/pkg/front_end/test/flow_analysis/reachability/data/switch.dart b/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
index 82e0b50..a257adb 100644
--- a/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
+++ b/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
@@ -15,3 +15,22 @@
   }
   3;
 }
+
+void case_falls_through_end(int i) {
+  switch (i) {
+    case 1:
+      1;
+  }
+  2;
+}
+
+/*member: all_cases_exit:doesNotComplete*/
+void all_cases_exit(int i) {
+  switch (i) {
+    case 1:
+      return;
+    default:
+      return;
+  }
+  /*stmt: unreachable*/ 1;
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
index 19c4b8f..81e631f 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
@@ -29,6 +29,17 @@
   }
 }
 
+void for_outerIsType_loopAssigned_body_emptyCondition(bool b, Object x) {
+  if (x is String) {
+    for (;;) {
+      if (!b) break;
+      x;
+      x = 42;
+    }
+    x;
+  }
+}
+
 void for_outerIsType_loopAssigned_condition(Object x) {
   if (x is String) {
     for (; (x = 42) > 0;) {
@@ -47,6 +58,16 @@
   }
 }
 
+void for_outerIsType_loopAssigned_updaters_emptyCondition(bool b, Object x) {
+  if (x is String) {
+    for (;; x = 42) {
+      if (!b) break;
+      x;
+    }
+    x;
+  }
+}
+
 void forEach_outerIsType_loopAssigned(Object x) {
   if (x is String) {
     for (var _ in [0, 1, 2]) {
@@ -77,6 +98,15 @@
   }
 }
 
+void collection_for_outerIsType_loopAssigned_body_emptyCondition(Object x) {
+  if (x is String) {
+    [
+      for (;;) [x, (x = 42)]
+    ];
+    x;
+  }
+}
+
 void collection_for_outerIsType_loopAssigned_condition(Object x) {
   if (x is String) {
     [for (; (x = 42) > 0;) x];
@@ -91,6 +121,13 @@
   }
 }
 
+void collection_for_outerIsType_loopAssigned_updaters_emptyCondition(Object x) {
+  if (x is String) {
+    [for (;; x = 42) x];
+    x;
+  }
+}
+
 void collection_forEach_outerIsType_loopAssigned(Object x) {
   if (x is String) {
     [
@@ -99,3 +136,10 @@
     x;
   }
 }
+
+void assign_var_declared_in_loop() {
+  for (int x = 0; x < 10; x++) {
+    bool b = true;
+    b = false;
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
index 9939bb7..ecaaa0a 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
@@ -19,3 +19,15 @@
     x;
   }
 }
+
+void case_falls_through_end(int i, Object o) {
+  switch (i) {
+    case 1:
+      if (o is! int) return;
+      /*int*/ o;
+      break;
+    case 2:
+      o;
+  }
+  o;
+}
diff --git a/pkg/front_end/test/incremental_bulk_compiler_full.dart b/pkg/front_end/test/incremental_bulk_compiler_full.dart
index cc73543..ad1a7f3 100644
--- a/pkg/front_end/test/incremental_bulk_compiler_full.dart
+++ b/pkg/front_end/test/incremental_bulk_compiler_full.dart
@@ -29,7 +29,7 @@
 import 'incremental_utils.dart' as util;
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
diff --git a/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart b/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
index 5399635..866104c 100644
--- a/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
+++ b/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
@@ -9,7 +9,7 @@
 import 'incremental_bulk_compiler_full.dart' show Context;
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
diff --git a/pkg/front_end/test/incremental_load_from_dill_test.dart b/pkg/front_end/test/incremental_load_from_dill_test.dart
index b88f426..d258364 100644
--- a/pkg/front_end/test/incremental_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_test.dart
@@ -54,13 +54,17 @@
 
 import "package:yaml/yaml.dart" show YamlList, YamlMap, loadYamlNode;
 
+import 'binary_md_dill_reader.dart' show DillComparer;
+
 import "incremental_utils.dart" as util;
 
 import 'package:front_end/src/fasta/fasta_codes.dart'
     show DiagnosticMessageFromJson, FormattedMessage;
 
+import 'utils/io_utils.dart' show computeRepoDir;
+
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
@@ -196,7 +200,7 @@
 Future<Map<String, List<int>>> createModules(
     Map module, final List<int> sdkSummaryData) async {
   final Uri base = Uri.parse("org-dartlang-test:///");
-  final Uri sdkSummary = base.resolve("vm_platform.dill");
+  final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
 
   MemoryFileSystem fs = new MemoryFileSystem(base);
   fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
@@ -263,7 +267,7 @@
 Future<Null> newWorldTest(List worlds, Map modules, bool omitPlatform) async {
   final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
   final Uri base = Uri.parse("org-dartlang-test:///");
-  final Uri sdkSummary = base.resolve("vm_platform.dill");
+  final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
   final Uri initializeFrom = base.resolve("initializeFrom.dill");
   Uri platformUri = sdkRoot.resolve("vm_platform_strong.dill");
   final List<int> sdkSummaryData =
@@ -286,7 +290,12 @@
         .readComponent(newestWholeComponent);
   }
 
+  int worldNum = 0;
   for (YamlMap world in worlds) {
+    worldNum++;
+    print("----------------");
+    print("World #$worldNum");
+    print("----------------");
     List<Component> modulesToUse;
     if (world["modules"] != null) {
       moduleComponents ??= new Map<String, Component>();
@@ -768,7 +777,24 @@
   }
   for (int i = 0; i < length; ++i) {
     if (a[i] != b[i]) {
-      Expect.fail("Data differs at byte ${i + 1}.");
+      print("Data differs at byte ${i + 1}.");
+
+      StringBuffer message = new StringBuffer();
+      message.writeln("Data differs at byte ${i + 1}.");
+      message.writeln("");
+      message.writeln("Will try to find more useful information:");
+
+      final String repoDir = computeRepoDir();
+      File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+      String binaryMdContent = binaryMd.readAsStringSync();
+
+      DillComparer dillComparer = new DillComparer();
+      if (dillComparer.compare(a, b, binaryMdContent, message)) {
+        message.writeln(
+            "Somehow the two different byte-lists compared to the same.");
+      }
+
+      Expect.fail(message.toString());
     }
   }
   Expect.equals(a.length, b.length);
@@ -798,11 +824,27 @@
   options ??= getOptions();
   TestIncrementalCompiler compiler =
       new TestIncrementalCompiler(options, input);
+  List<int> bytes =
+      await normalCompileToBytes(input, options: options, compiler: compiler);
+  new File.fromUri(output).writeAsBytesSync(bytes);
+  return compiler.initializedFromDill;
+}
+
+Future<List<int>> normalCompileToBytes(Uri input,
+    {CompilerOptions options, IncrementalCompiler compiler}) async {
+  Component component = await normalCompileToComponent(input,
+      options: options, compiler: compiler);
+  return util.postProcess(component);
+}
+
+Future<Component> normalCompileToComponent(Uri input,
+    {CompilerOptions options, IncrementalCompiler compiler}) async {
+  options ??= getOptions();
+  compiler ??= new TestIncrementalCompiler(options, input);
   Component component = await compiler.computeDelta();
   util.throwOnEmptyMixinBodies(component);
   util.throwOnInsufficientUriToSource(component);
-  new File.fromUri(output).writeAsBytesSync(util.postProcess(component));
-  return compiler.initializedFromDill;
+  return component;
 }
 
 Future<bool> initializedCompile(
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
index 1c14ade..f175cd0 100644
--- a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
@@ -6,9 +6,11 @@
 
 import 'foo2.dart';
 import 'foo3.dart';
+import 'foo4.dart';
 
 foo() {
   print("Hello from foo!");
   foo2();
   foo3();
+  foo4();
 }
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
index 8ff3e3c4..6ffcfd9 100644
--- a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// .packages specifies 2.5, this library tries to go above that, which is an
-// error. The library stays on the .packages specified one (2.5) and an error is
-// issued.
+// .packages specifies 2.5, this library tries to go above that, which is fine.
 
-/*error: LanguageVersionTooHigh*/
 // @dart = 2.6
 
-/*library: languageVersion=2.5*/
+/*library: languageVersion=2.6*/
 
 foo3() {
   print("Hello from foo3!");
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart
new file mode 100644
index 0000000..9591a55
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// .packages specifies 2.5, this library tries to go above that, which is fine,
+// except it still has to be within the range of the sdk. The library stays on
+// the .packages specified one (2.5) and an error is issued.
+
+/*error: LanguageVersionTooHigh*/
+// @dart = 2.9
+
+/*library: languageVersion=2.5*/
+
+foo4() {
+  print("Hello from foo4!");
+}
diff --git a/pkg/front_end/test/language_versioning/language_versioning_test.dart b/pkg/front_end/test/language_versioning/language_versioning_test.dart
index 510bba0..691df94 100644
--- a/pkg/front_end/test/language_versioning/language_versioning_test.dart
+++ b/pkg/front_end/test/language_versioning/language_versioning_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io' show Directory, Platform;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
 import 'package:front_end/src/fasta/messages.dart' show FormattedMessage;
 import 'package:front_end/src/testing/id.dart' show ActualData, Id;
 import 'package:front_end/src/testing/id_testing.dart'
@@ -11,9 +12,9 @@
 import 'package:front_end/src/testing/id_testing_helper.dart'
     show
         CfeDataExtractor,
-        InternalCompilerResult,
         DataComputer,
-        defaultCfeConfig,
+        InternalCompilerResult,
+        TestConfig,
         createUriForFileName,
         onFailure,
         runTestFor;
@@ -21,8 +22,9 @@
 
 main(List<String> args) async {
   // Fix default/max major and minor version so we can test it.
-  Library.defaultLangaugeVersionMajor = 2;
-  Library.defaultLangaugeVersionMinor = 8;
+  // This config sets it to 2.8.
+  TestConfigWithLanguageVersion cfeConfig =
+      new TestConfigWithLanguageVersion(cfeMarker, "cfe");
 
   Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
   await runTests(dataDir,
@@ -30,8 +32,17 @@
       supportedMarkers: [cfeMarker],
       createUriForFileName: createUriForFileName,
       onFailure: onFailure,
-      runTest: runTestFor(
-          const LanguageVersioningDataComputer(), [defaultCfeConfig]));
+      runTest: runTestFor(const LanguageVersioningDataComputer(), [cfeConfig]));
+}
+
+class TestConfigWithLanguageVersion extends TestConfig {
+  TestConfigWithLanguageVersion(String marker, String name)
+      : super(marker, name);
+
+  @override
+  void customizeCompilerOptions(CompilerOptions options) {
+    options.currentSdkVersion = "2.8";
+  }
 }
 
 class LanguageVersioningDataComputer extends DataComputer<String> {
diff --git a/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart
new file mode 100644
index 0000000..36d0799
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show Platform, Process, ProcessResult;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:kernel/ast.dart' as kernel show Library;
+
+import '../utils/io_utils.dart';
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
+
+main(List<String> args) async {
+  ProcessResult result = await Process.run(
+      "python", ["tools/make_version.py", "--no_git", "-q"],
+      workingDirectory: repoDir);
+
+  String stdout = result.stdout.toString();
+  String stderr = result.stderr.toString();
+  int exitCode = result.exitCode;
+
+  print("--- stdout ---");
+  print(stdout);
+  print("--- stderr ---");
+  print(stderr);
+  print("---exit code ---");
+  print(exitCode);
+
+  // E.g. "2.6.0-edge" (without the quotes).
+  String versionString = stdout.split("\n")[0];
+  List<String> dotSeparatedParts = versionString.split(".");
+  int major = int.tryParse(dotSeparatedParts[0]);
+  int minor = int.tryParse(dotSeparatedParts[1]);
+
+  if (kernel.Library.defaultLanguageVersionMajor != major ||
+      kernel.Library.defaultLanguageVersionMinor != minor) {
+    throw "Kernel defaults "
+        "${kernel.Library.defaultLanguageVersionMajor}"
+        "."
+        "${kernel.Library.defaultLanguageVersionMinor}"
+        " does not match output from make_version.py ($major.$minor)";
+  } else {
+    print("Kernel version matches.");
+  }
+
+  CompilerOptions compilerOptions = new CompilerOptions();
+
+  List<String> dotSeparatedPartsFromOptions =
+      compilerOptions.currentSdkVersion.split(".");
+  int majorFromOptions = int.tryParse(dotSeparatedPartsFromOptions[0]);
+  int minorFromOptions = int.tryParse(dotSeparatedPartsFromOptions[1]);
+  if (majorFromOptions != major || minorFromOptions != minor) {
+    throw "CompilerOptions defaults "
+        "${majorFromOptions}.${minorFromOptions}"
+        " does not match output from make_version.py ($major.$minor)";
+  } else {
+    print("CompilerOptions default version matches.");
+  }
+}
diff --git a/pkg/front_end/test/lint_test.dart b/pkg/front_end/test/lint_test.dart
index f39f95c7..f674e25 100644
--- a/pkg/front_end/test/lint_test.dart
+++ b/pkg/front_end/test/lint_test.dart
@@ -32,7 +32,7 @@
     show Chain, ChainContext, Result, Step, TestDescription, runMe;
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
@@ -227,7 +227,7 @@
     }
   }
 
-  void endFields(Token staticToken, Token covariantToken, Token lateToken,
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
       Token varFinalOrConst, int count, Token beginToken, Token endToken) {
     if (!_latestType.type) {
       onProblem(
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index 7d72c5b..f7c20bf 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -6,7 +6,6 @@
 src/fasta/builder/class_builder/ImportsTwice: Fail
 src/fasta/builder/field_builder/ImportsTwice: Fail
 src/fasta/builder/prefix_builder/ImportsTwice: Fail
-src/fasta/builder/procedure_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/old_dill_test.dart b/pkg/front_end/test/old_dill_test.dart
index df757c40..f8b22f8 100644
--- a/pkg/front_end/test/old_dill_test.dart
+++ b/pkg/front_end/test/old_dill_test.dart
@@ -20,7 +20,7 @@
     await checkDill();
     return null;
   }
-  await runMe(arguments, createContext, "../testing.json");
+  await runMe(arguments, createContext, configurationPath: "../testing.json");
   await checkDill();
 }
 
diff --git a/pkg/front_end/test/read_dill_from_binary_md_test.dart b/pkg/front_end/test/read_dill_from_binary_md_test.dart
new file mode 100644
index 0000000..cc738f1
--- /dev/null
+++ b/pkg/front_end/test/read_dill_from_binary_md_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async' show Future;
+
+import 'dart:io' show File, Platform;
+
+import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
+
+import 'binary_md_dill_reader.dart' show BinaryMdDillReader;
+
+import 'incremental_load_from_dill_test.dart'
+    show getOptions, normalCompileToBytes;
+
+import 'utils/io_utils.dart' show computeRepoDir;
+
+main() async {
+  await testDart2jsCompile();
+}
+
+Future<void> testDart2jsCompile() async {
+  final Uri dart2jsUrl = Uri.base.resolve("pkg/compiler/bin/dart2js.dart");
+  Stopwatch stopwatch = new Stopwatch()..start();
+  List<int> bytes = await normalCompileToBytes(dart2jsUrl,
+      options: getOptions()..target = new NoneTarget(new TargetFlags()));
+  print("Compiled dart2js in ${stopwatch.elapsedMilliseconds} ms");
+
+  stopwatch.reset();
+  File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+  String binaryMdContent = binaryMd.readAsStringSync();
+  print("Read binary.md in ${stopwatch.elapsedMilliseconds} ms");
+
+  stopwatch.reset();
+  BinaryMdDillReader binaryMdDillReader =
+      new BinaryMdDillReader(binaryMdContent, bytes);
+  binaryMdDillReader.attemptRead();
+  print("Parsed dart2js compiled bytes via binary.md "
+      "in ${stopwatch.elapsedMilliseconds} ms");
+}
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
diff --git a/pkg/front_end/test/scanner_fasta_test.dart b/pkg/front_end/test/scanner_fasta_test.dart
index 02cd12f..c9ae5b2 100644
--- a/pkg/front_end/test/scanner_fasta_test.dart
+++ b/pkg/front_end/test/scanner_fasta_test.dart
@@ -97,6 +97,8 @@
     }
 
     for (int byte0 = 1; byte0 <= 0xFF; ++byte0) {
+      List<int> bytes = [byte0, 0];
+      scanBytes(bytes);
       for (int byte1 = 1; byte1 <= 0xFF; ++byte1) {
         List<int> bytes = [byte0, byte1, 0];
         scanBytes(bytes);
diff --git a/pkg/front_end/test/spell_checking_list_blacklist.txt b/pkg/front_end/test/spell_checking_list_blacklist.txt
new file mode 100644
index 0000000..9649873
--- /dev/null
+++ b/pkg/front_end/test/spell_checking_list_blacklist.txt
@@ -0,0 +1,79 @@
+# 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.
+
+# Blank lines and comments are ignored.
+# Comments can also be inline like 'correct # this is ok'.
+# Note that at least one space before the hash is required.
+
+
+alread
+chnage
+clonable
+comile
+complation
+conditoinal
+conected
+constructer
+constructers
+contaning
+contol
+covarint
+depencencies
+detemination
+diagnotics
+down't
+effeciency
+erronious
+errornious
+evaluted
+explaination
+expresison
+expressoin
+gurantees
+hiearchy
+hierachy
+independendent
+infered
+instantaite
+instantating
+instantition
+instesection
+internel
+keybord
+libarary
+librares
+neame
+neccessary
+normaly
+nullabiliity
+obect
+occured
+occurence
+ocurred
+opreations
+Orignially
+outtermost
+phisical
+plaform
+poluted
+preceeded
+previosly
+priotity
+proram
+recomile
+resently
+satifying
+seach
+singluar
+Specifiction
+staments
+statment
+stubstitution
+subsitutions
+subtring
+suffient
+terminted
+tood
+unlinke
+valiation
\ No newline at end of file
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 1475e26..7a131c6 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -6,52 +6,110 @@
 # Comments can also be inline like 'correct # this is ok'.
 # Note that at least one space before the hash is required.
 
+a+b
+abbreviate
+abcdef
+abs
+accounting
+accounts
+accumulated
+accumulating
+across
+affecting
+afterwards
+agree
 ahe
 ai
 aiki
 aka
+alexmarkov
+aligned
+alive
+allocate
+altered
+analogous
+annotate
 ansi
+answering
+anyone
 ap
 api
+app
 arg
 args
 argument1
+arise
+arises
+arising
+arity
+artifact
+artificial
+asgerf
 askesc
+assigning
+assigns
 ast
 asy
 atm
+atom
+atoms
+attributes
 automagically
+awaiting
 b
 b23d3b125e9d246e07a2b43b61740759a0dace
 backping
 bang
 bar
+basically
+batch
 baz
 bazel
 bb
+beforehand
+behave
+bellow
+belonging
 benchmarks
 bf
 bi
+bias
+biased
 bin
+binder
+binders
+binds
 bj
-blah
 blob
+blocking
 bn
+bo
 bodied
+body's
 bof
 bom
+bother
+breadcrumbs
 brianwilkerson
 bs
 bsd
+bslash
+buffered
 builder`s
 bulder
+bulk
+bump
+bypassing
 c
+caches
 callee
 caller's
 callers
+callsite
 came
 canonicalizer
 cant
+cardinality
 caret
 carets
 carriage
@@ -67,54 +125,127 @@
 ck
 cl
 claim
+clarification
+clashes
 class's
+clazz
 cls
 cn
+co
 codebase
 codec
 codes
+collision
 com
+combinations
 combinator
+combine2
 combiner
+compared
+compares
+completes
+complicating
 component's
+compressed
+compression
+concat
+concatenate
+concerned
 cond
+condensed
 config
 configs
+configured
 constness
+consult
+consumers
+container
+containers
+continuations
 contra
+convention
 core
 core's
+corrected
+cosmetic
+counters
 cr
+creator
+criterion
+cross
+cruft
+cryptic
+ctx
 cut
 cwd
+cyclically
 d
 d11e
 dag
+dangling
 danrubel
 daringfireball
 dartbug
 dartdoc
 dartlang
+dc
 ddc
 ddk
+dea112b090073317d
+debuggable
 dec
 decl
+decoupled
+decreases
+deemed
+deepest
+deeply
+degrades
+degree
 del
+delimit
+demands
 demangle
 demangled
 deps
-desc
+dereferenced
+dereferencing
+descent
+deserializer
+deserializers
+deserializes
+deserializing
+design
+despite
+destination
+destinations
+destroy
+deterministic
 dev
 diff
 diffs
 digest
 digests
+dijkstra's
+directed
+directions
+dirty
+disallow
+disambiguator
+disjoint
+dispatched
+divided
 dmitryas
 doc
 docs
 dom
-dpkg
+doubles
+downcasts
+downloaded
+downloading
 dq
+dquote
+dst
 dummy
 e
 easy
@@ -123,77 +254,179 @@
 ed
 eek
 ef
+effects
+efficient
+efficiently
 elem
+eliminating
 elt
 em
 emit
+emits
 emitted
+emitting
 en
+enforce
+enforced
+enumerates
 env
 eof
 eq
+equation
+erasure
+estimate
 eval
+excludes
+exhausted
+existentially
 exp
+expense
 exportee
 exportees
 expr
+expression's
 ext
+extenders
+extracted
+extracts
 f
+faced
+factor
 fangorn
 fasta
+favoring
+fc
 fe
 feff
 ff
+fff
 ffff
+fffff
 ffi
+file's
+filenames
+firsts
+fishy
 fishythefish
+fleshed
+float64
 floitsch
+flowed
+flushed
+flutter's
 fn
 fo
 foo
 foobar
 formed
 former
+fortunately
+fourth
+framework
+freely
 frontend
+frontends
 fs
+function's
+fuse
 futured
 g
+generation
 gets
+getting
 gft
-git
 github
 glb
+globally
 gn
 googlesource
 goto
 gotos
+gradually
+graphs
 gt
+guarantee
+guarded
 gypi
 gz
 gzip
 gzipped
 h
+hashes
+hashing
+heap
+height
+hello
+helpful
 hfs
+highlight
+highlighting
+highlights
 hillerstrom
+histogram
+hit
 hoc
+hoisted
 href
 html
 https
+human
 i
+i'll
 id
+identifies
+identifying
 ideographic
 idn
 ids
 iff
+il
+immutability
 impl
+implementers
+imply
+implying
+importantly
 inc
+incomparable
+incremented
+independently
+indexer
+indexing
+indirection
+individual
+informative
 infos
 init
+initializations
+initializer's
+insertion
+inspector
+inspired
+instanceof
+instantiator
+intentionally
+interior
+interleaved
+intermediate
+interpolations
+intersects
+interval
+intervals
 ints
+invariants
 io
+is64
 issuecomment
+iterables
+iterating
+iterations
+iterators
 j
+jacobr
+jakemac
 java
+jenkins
 jensj
 johnniwinther
 js
@@ -207,27 +440,45 @@
 klass
 kmillikin
 kustermann
+kv
 l
+lacks
 lang
+largest
+lattice
+layer
 leafp
 len
+lets
+letting
 lex
 lexemes
 lf
 lhs
 lib
 libs
+lifted
+lifter
+linearized
+lives
 lm
+locationd
+lots
+lparen
 lry
 ls
 lt
+lub
 lvalue
 m
+maintaining
+mangled
+manipulation
 markdown
 mb
 md
 me
-met
+merely
 meta
 method1a
 method1b
@@ -237,131 +488,288 @@
 method3b
 mi
 min
+mixers
 mk
 mm
 mn
 monomorphic
+moves
 msg
+murmur
 n
 na
+nameless
+namer
+natively
 nbsp
 ncs
 ncurses
 nd
+near
+neighboring
 nextnext
 ni
+nine
 nj
 nk
 nnbd
+node's
+nonimplementation
+notion
 nr
 ns
 nsm
+nth
+nullabilities
 nullability
 nullable
+nullary
+nulls
 o
 obj
+observe
+obstruct
+occasionally
+occupied
+occurences
 offs
 ogham
+oked
 op
 opt
+optimizations
 opts
+ordered
+orders
 ordinal
 org
+orphans
 os
+overlap
+overloader
 overshadowed
+overwrite
+overwriting
+ownership
 p
 p1
 p2
+par
+parallel
 param
+parameter's
+parametrized
 params
 paren
 parens
+parenteses
+particularly
 path
-pathos
 paulberry
 pay
 payload
+payloads
 pdf
 per
 perf
+permit
 pi
+picking
 pkg
 pm
 pn
 pointwise
+polluted
+popped
 pos
+possibility
 postfix
+pow
+pragma
 pre
 prebuilt
+preorder
 prev
+prime
 printer
 printf
 println
 proc
+producers
+product
+progresses
+proof
+prop
+propose
+proposed
 proto
 ps
+pulled
+pure
+puts
 q
 q'i
 qi
 qm
 quad
+quantified
+queries
+quick
+quoted
 r
+r'\f
+r'\r
 r'\s
+r'\t
+r'\u
+r'\v
+r'$creation
 radix
+raises
 ran
+randomly
+ranges
+ranked
+ratio
 re
 reach
+react
+realign
 reassigned
 rebind
 rebuild
+recall
+received
 recompiled
 recompiling
 recompute
 recomputed
+recreate
+recursion
 red
+redeclared
 redirectee
+redirector
 reexports
 ref
 reflect
 reg
+regis
 rehash
+reindexed
+reissued
 rejoin
+relatively
 relativize
+relax
+relaxes
+remapped
+remedy
+removal
+remover
 reparse
+replacer
+replaces
+repo
+repositories
+requirement
 res
+residue
+respond
+restriction
+resumed
+rewrites
+rewrote
 rhs
 ri
+rightmost
 rn
 rnystrom
+role
+room
+rooted
+roughly
+rounding
+rparen
+runnable
 s
 sb
 scheglov
+scoped
+scoping
 sdk's
+seconds
+sections
+selectors
+semantically
+separators
+sequencing
+serializables
+serializer
+serializers
+serve
 server
 service
 setaf
 sh
+sha1hash
+shadowed
+shallow
 shas
+shrinking
+shru
 si
+sibling
+siblings
+sides
 sigmund
+significant
+simplify
+singleton
+sinker
+site
 six
 size
+sizes
 sj
 slash
 slb
+slots
+slowing
 smi
 sn
 socket
+sole
+solely
+somewhat
+spaced
+sparse
 spec
 spec'ed
+specially
+specifics
+speeding
+spend
+spuriously
 sq
+sra
 src
 st
+stability
+stacktrace
+stacktraces
+stale
+statics
 stderr
 stdin
-stdio
 stdout
 stmt
+str
+streaming
+strict
+stringified
+stringify
+structures
 stub
 stubs
 stx
@@ -369,16 +777,36 @@
 subexpression
 subexpression's
 subexpressions
+subnode
+subnodes
+subscription
+subsection
+subsections
 subst
 substed
+substitutes
+substitutor
+sum
+summarizing
 superclasses
 superinitializer
+superinterfaces
 supernode
 supers
+suppose
+suspended
 svg
 sw
+swapped
+sweep
+synchronously
 synth
 t
+tagged
+tagger
+tags
+taking
+team
 tear
 tearing
 tearoff
@@ -386,17 +814,23 @@
 tell
 tells
 temp
+temporaries
+temps
 term
 termcap
+terminator
+tester
 tex
 th
 ti
 tick
 ticker
 tid
+ties
 tiki
 tilde
 till
+tiny
 tj
 tm
 tmp
@@ -405,34 +839,81 @@
 token's
 tokenize
 tokenized
+tolerate
+tolerated
+toplevel
+topological
+tops
 tput
+tracker
+transformers
+transforming
+translation
+traversal
+traverse
+trees
+tricky
+trips
 ts
 tty
+tuple
+tuple2
+tuple3
+tuple4
 typeref
 u
+u001b
+ufeff
 ui
 uint
 uint16
 uint32
 uint8
+umbrella
 un
+unaffected
 unalias
+unaligned
+unaltered
+unassigned
+unbound
 uncomment
+uncommon
+unconditionally
 unconstrained
+undeclare
 unequal
 unescape
 unexact
 unfinalized
+unfolds
 unfuture
 unfutured
+unguarded
+unifiable
+unification
+unifier
+unify
+unions
+uniqueness
+universally
 unlinked
 unlower
+unordered
+unpaired
 unparsed
-update2018
+unpleasant
+unreachable
+unshadowed
+unwraps
+unzip
+upcast
 ur
 uri's
 url
 urls
+usr
+usually
 utf16
 utf8
 util
@@ -441,39 +922,71 @@
 variable's
 variance
 variances
+variant
+variants
+vary
 vegorov
+versa
+vice
+violated
+visit*
+visitors
+visits
+vm's
+vs
 vtab
 w
+wanted
+waste
+watch
 wc
+weird
 weren't
 werror
+whatnot
+whichever
+widget
+widgets
 wiki
 wikipedia
 with1
+worthwhile
 writeln
 wrt
 www
 x
 x0
 x00
+x00003fff
+x0007ffff
+x03ffffff
 x10
 x10ffff
 x180
 x1b
 x1f
 x1ff
+x1fffffff
 x2
 x200
 x202
 x205
 x3
+x3f
+x3fffffff
 x5
 x7
+x7fff
+x90
+x9ddfea08eb
+xbb
+xbf
 xcodebuild
 xd
 xdbff
 xdc
 xdfff
+xef
 xi
 xm
 xn
@@ -481,6 +994,8 @@
 xterm
 xx
 xxxx
+xxxxxx
+xxxxxxx
 y
 yaml
 yet
@@ -489,6 +1004,7 @@
 z
 zi
 zip
+zipped
 zn
 zone
 zoned
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 0b43a76..056b0f5 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -32,6 +32,7 @@
 accessing
 accessor
 accessors
+accidental
 accidentally
 accordance
 according
@@ -79,6 +80,7 @@
 algorithm
 algorithms
 alias
+alignment
 all
 allocated
 allocating
@@ -218,6 +220,7 @@
 backwards
 bad
 balanced
+bare
 base
 based
 basic
@@ -334,6 +337,7 @@
 canonicalized
 capabilities
 capability
+capable
 capital
 capture
 captured
@@ -386,6 +390,7 @@
 circularities
 circularity
 circumstances
+clashing
 class
 classes
 classic
@@ -512,6 +517,7 @@
 connection
 consequence
 consequently
+conservative
 conservatively
 consider
 considered
@@ -593,6 +599,7 @@
 couldn't
 count
 counter
+counting
 counts
 couple
 covariance
@@ -603,16 +610,19 @@
 covers
 crash
 crashed
+crashes
 crashing
 create
 created
 creates
 creating
 creation
+crossed
 curly
 current
 currently
 custom
+customize
 cyan
 cycle
 cycles
@@ -819,6 +829,7 @@
 early
 easier
 easiest
+easily
 edge
 edges
 edit
@@ -855,10 +866,12 @@
 encoder
 encodes
 encoding
+encounter
 encountered
 encounters
 end
 ended
+endian
 ending
 endings
 ends
@@ -877,6 +890,7 @@
 entering
 entire
 entirely
+entirety
 entities
 entity
 entity's
@@ -889,6 +903,7 @@
 equal
 equality
 equals
+equivalence
 equivalent
 equivalents
 erroneous
@@ -899,6 +914,7 @@
 escapes
 escaping
 essence
+essentials
 etc
 evaluate
 evaluated
@@ -924,6 +940,7 @@
 exceeded
 except
 exception
+exceptional
 exceptions
 exclamation
 exclude
@@ -1237,6 +1254,7 @@
 ignores
 ignoring
 illegal
+imaginary
 imitation
 immediate
 immediately
@@ -1352,6 +1370,8 @@
 instantiation
 instantiations
 instead
+instruction
+instructions
 instrumentation
 instrumented
 int
@@ -1402,6 +1422,7 @@
 invocation
 invocation's
 invocations
+invokable
 invoke
 invoked
 invokes
@@ -1608,6 +1629,7 @@
 matter
 maturity
 max
+maximum
 may
 maybe
 mean
@@ -1662,6 +1684,7 @@
 mock
 mode
 model
+models
 modes
 modifiable
 modification
@@ -1812,6 +1835,7 @@
 operator
 operators
 opposed
+opted
 optimistically
 optimization
 optimize
@@ -1830,6 +1854,7 @@
 originally
 originate
 originated
+originates
 originating
 origins
 orphan
@@ -1906,6 +1931,7 @@
 paths
 pattern
 peek
+pending
 percent
 perform
 performance
@@ -1925,8 +1951,10 @@
 pick
 picked
 pipeline
+piping
 pivot
 place
+places
 placed
 placeholder
 placeholders
@@ -1976,6 +2004,7 @@
 precision
 preclude
 precondition
+predefined
 predicate
 preemptively
 prefer
@@ -1985,6 +2014,7 @@
 prefix
 prefixed
 prefixes
+prelude
 prepare
 prepared
 preparing
@@ -2084,6 +2114,7 @@
 qualifier
 qualifiers
 quality
+queried
 query
 question
 queue
@@ -2109,6 +2140,7 @@
 reads
 ready
 real
+realigned
 realized
 really
 reason
@@ -2156,6 +2188,7 @@
 refers
 refine
 refinement
+reflecting
 regardless
 region
 regions
@@ -2173,11 +2206,13 @@
 related
 relation
 relational
+relations
 relationship
 relationships
 relative
 release
 relevant
+relied
 relies
 reloads
 rely
@@ -2189,12 +2224,14 @@
 remember
 remembered
 remembers
+reminder
 remote
 remove
 removed
 removes
 removing
 rename
+renamed
 renaming
 repeated
 repeatedly
@@ -2237,6 +2274,7 @@
 resolving
 resources
 respect
+respected
 respective
 respectively
 respects
@@ -2256,6 +2294,7 @@
 retain
 retained
 rethrow
+retired
 retrieve
 retrieved
 retrieves
@@ -2298,6 +2337,7 @@
 runtime
 safe
 safely
+safety
 said
 sake
 same
@@ -2350,6 +2390,7 @@
 sends
 sense
 sent
+sentence
 sentinel
 separate
 separated
@@ -2392,6 +2433,7 @@
 shouldn't
 show
 shown
+shows
 shrink
 side
 sign
@@ -2401,6 +2443,7 @@
 signatures
 signed
 silent
+silently
 silly
 similar
 similarly
@@ -2452,6 +2495,7 @@
 sorted
 sorting
 sorts
+sought
 source
 sources
 space
@@ -2483,6 +2527,7 @@
 stamps
 standalone
 standard
+stands
 star
 start
 started
@@ -2560,6 +2605,7 @@
 sufficient
 sufficiently
 suffix
+suffixes
 suggested
 suitable
 summaries
@@ -2608,6 +2654,7 @@
 systems
 tab
 table
+tables
 tabs
 tag
 tail
@@ -2749,6 +2796,7 @@
 turn
 turned
 turning
+turns
 tv
 twice
 two
@@ -2760,9 +2808,11 @@
 typically
 typing
 unable
+unambiguous
 unary
 unbalanced
 unbind
+uncertain
 unchanged
 unclaimed
 unclear
@@ -2771,6 +2821,7 @@
 underlying
 underscore
 understand
+understood
 unevaluated
 unexpected
 unfinished
@@ -2799,6 +2850,7 @@
 unnamed
 unnecessarily
 unnecessary
+unparsable
 unpromoted
 unread
 unrecognized
@@ -2872,6 +2924,7 @@
 verify
 verifying
 version
+versioning
 versions
 vertex
 vertical
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index 0ed2f9a..cbc5036 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -6,6 +6,7 @@
 # Comments can also be inline like 'correct # this is ok'.
 # Note that at least one space before the hash is required.
 
+argument(s)
 b
 c
 compilercontext.runincontext
@@ -48,4 +49,4 @@
 type3.#name
 u
 v
-x
\ No newline at end of file
+x
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 18a1ce4..6786412 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -13,17 +13,13 @@
 aaa
 abc
 abcompile
-across
 actions
 affected
 albeit
-alive
 allocations
 anon
-app
 approval
 approximation
-arity
 asserter
 auth
 autobianchi
@@ -35,7 +31,6 @@
 bailout
 bash
 bat
-batch
 bbb
 bc
 bench
@@ -43,6 +38,8 @@
 besides
 beta
 bigger
+blacklist
+blah
 blindly
 blocked
 blorp
@@ -52,7 +49,6 @@
 brave
 brown
 builddir
-bulk
 bulk2
 bulkcompile
 c's
@@ -76,12 +72,12 @@
 collisions
 commit
 companion
+comparer
 comparisons
 compilations
 compiler's
 complement
 completers
-completes
 confirm
 consecutive
 considering
@@ -94,15 +90,16 @@
 cumulative
 dacoharkes
 daemon
-dangling
 dartanalyzer
 dartfile
 dashes
 day
 db
+decrements
 def
 depended
 depfile
+desc
 deviation
 dfast
 dictionaries
@@ -119,7 +116,6 @@
 doctype
 doesnt
 dog
-downcasts
 downstream
 dumping
 dupe
@@ -130,7 +126,6 @@
 ease
 ec
 edits
-efficient
 elapse
 ell
 entrypoint
@@ -139,7 +134,6 @@
 err
 everytime
 evicting
-excludes
 exe
 execute
 exercised
@@ -157,7 +151,6 @@
 falling
 favors
 fibonacci
-filenames
 filesystem
 finder
 fisk
@@ -167,23 +160,20 @@
 forces
 foreign
 fox
-framework
 fulfill
 func
 futures
 gallery
 gamma
 gen
-generation
 generators
-glb
+git
 greeting
 gtgt
 gulp
 gunk
 hackish
 harness
-hello
 hest
 heuristics
 hi
@@ -202,8 +192,7 @@
 inclosure
 increased
 incrementally
-individual
-insertion
+increments
 inspect
 insufficient
 intact
@@ -211,20 +200,16 @@
 interpolate
 inv
 invalidating
-invariants
 isolate
 isolates
 iter
-iterations
 jumped
+kernels
 ko
 la
-lacks
-largest
 lc
 ld
 le
-lets
 lightly
 likewise
 linebreaks
@@ -235,13 +220,13 @@
 logd
 logs
 loopback
-lots
-lub
 mac
 maker
 matters
 mc
+mds
 measured
+met
 metric
 metrics
 mf
@@ -257,8 +242,6 @@
 negatable
 ninja
 nonexisting
-notion
-nullary
 numerator
 observable
 observatory
@@ -266,7 +249,6 @@
 okay
 oracle
 overlay
-parametrized
 party
 pause
 periodic
@@ -284,17 +266,18 @@
 producer
 profiler
 promotes
-prop
 propagated
 protected
 provider
-pure
+pubspec
 pv
 px
 py
-quick
+python
 quot
+r"
 r"\s
+r"k
 rd
 reachability
 reality
@@ -308,14 +291,16 @@
 regenerate
 regressions
 reload
+remap
+remaps
 repeating
-repo
 repro
 resource
 respected
 response
 retains
 rev
+risky
 say
 scans
 screen
@@ -323,48 +308,34 @@
 sdkroot
 sdks
 secondary
-seconds
 segment
-shadowed
 shipped
 shot
 signalled
-simplify
-site
-somewhat
 spans
 spell
 spellcheck
-spelled
 spelling
 spent
 splitting
 sqrt
-statics
 std
-str
+stdio
 strip
 strongest
-structures
 stub's
 stupid
 subcommand
-subscription
+subdir
 subtool
 subtools
 suite
-sum
 summarization
 summarized
 superinterface
 supermixin
 supplement
-swapped
-tags
-team
 templates
-terminator
-tester
 thereof
 thing
 threw
@@ -373,11 +344,8 @@
 timing
 timings
 title
-toplevel
 tpt
-transforming
 transitively
-translation
 triangle
 trigger
 triggers
@@ -389,31 +357,22 @@
 typeargs
 typeparam
 typeparambounds
-unassigned
 unawaited
 unbreak
-unification
-unordered
-unreachable
 unregistered
 untransformed
+untrimmed
 uppercase
 upward
-usr
+uses8
 usual
 val
-variants
+vars
 verbatim
-versa
 versioning
-vice
-vm's
-vs
 waiting
 walt
-wanted
 warmup
-weird
 whitelist
 whitelisting
 wins
diff --git a/pkg/front_end/test/spell_checking_utils.dart b/pkg/front_end/test/spell_checking_utils.dart
index 7c3c21774..479effa 100644
--- a/pkg/front_end/test/spell_checking_utils.dart
+++ b/pkg/front_end/test/spell_checking_utils.dart
@@ -9,6 +9,8 @@
   cfeMessages,
   cfeCode,
   cfeTests,
+  // The blacklist is special and is always loaded!
+  blacklist,
 }
 
 Map<Dictionaries, Set<String>> loadedDictionaries;
@@ -20,6 +22,7 @@
 
   List<String> wrongWords;
   List<int> wrongWordsOffset;
+  List<bool> wrongWordBlacklisted;
   List<int> wordOffsets = new List<int>();
   List<String> words =
       splitStringIntoWords(s, wordOffsets, splitAsCode: splitAsCode);
@@ -29,6 +32,7 @@
     bool found = false;
     for (int j = 0; j < dictionaries.length; j++) {
       Dictionaries dictionaryType = dictionaries[j];
+      if (dictionaryType == Dictionaries.blacklist) continue;
       Set<String> dictionary = loadedDictionaries[dictionaryType];
       if (dictionary.contains(word)) {
         found = true;
@@ -40,16 +44,22 @@
       wrongWords.add(word);
       wrongWordsOffset ??= new List<int>();
       wrongWordsOffset.add(offset);
+      wrongWordBlacklisted ??= new List<bool>();
+      wrongWordBlacklisted
+          .add(loadedDictionaries[Dictionaries.blacklist].contains(word));
     }
   }
-  return new SpellingResult(wrongWords, wrongWordsOffset);
+
+  return new SpellingResult(wrongWords, wrongWordsOffset, wrongWordBlacklisted);
 }
 
 class SpellingResult {
   final List<String> misspelledWords;
   final List<int> misspelledWordsOffset;
+  final List<bool> misspelledWordsBlacklisted;
 
-  SpellingResult(this.misspelledWords, this.misspelledWordsOffset);
+  SpellingResult(this.misspelledWords, this.misspelledWordsOffset,
+      this.misspelledWordsBlacklisted);
 }
 
 void ensureDictionariesLoaded(List<Dictionaries> dictionaries) {
@@ -71,6 +81,14 @@
   }
 
   loadedDictionaries ??= new Map<Dictionaries, Set<String>>();
+  // Ensure the blacklist is loaded.
+  Set<String> blacklistDictionary = loadedDictionaries[Dictionaries.blacklist];
+  if (blacklistDictionary == null) {
+    blacklistDictionary = new Set<String>();
+    loadedDictionaries[Dictionaries.blacklist] = blacklistDictionary;
+    addWords(dictionaryToUri(Dictionaries.blacklist), blacklistDictionary);
+  }
+
   for (int j = 0; j < dictionaries.length; j++) {
     Dictionaries dictionaryType = dictionaries[j];
     Set<String> dictionary = loadedDictionaries[dictionaryType];
@@ -78,6 +96,13 @@
       dictionary = new Set<String>();
       loadedDictionaries[dictionaryType] = dictionary;
       addWords(dictionaryToUri(dictionaryType), dictionary);
+      // Check that no good words occur in the blacklist.
+      for (String s in dictionary) {
+        if (blacklistDictionary.contains(s)) {
+          throw "Word '$s' in dictionary $dictionaryType "
+              "is also in the blacklist.";
+        }
+      }
     }
   }
 }
@@ -96,6 +121,9 @@
     case Dictionaries.cfeTests:
       return Uri.base
           .resolve("pkg/front_end/test/spell_checking_list_tests.txt");
+    case Dictionaries.blacklist:
+      return Uri.base
+          .resolve("pkg/front_end/test/spell_checking_list_blacklist.txt");
   }
   throw "Unknown Dictionary";
 }
@@ -107,9 +135,9 @@
   String regExpStringInner = r"\s-=\|\/,";
   if (splitAsCode) {
     // If splitting as code also split by "_", ":", ".", "(", ")", "<", ">",
-    // "[", "]", "{", "}", "@", "&", "#", "?". (As well as doing stuff to camel
-    // casing further below).
-    regExpStringInner = "${regExpStringInner}_:\\.\\(\\)<>\\[\\]\{\}@&#\\?";
+    // "[", "]", "{", "}", "@", "&", "#", "?", "%".
+    // (As well as doing stuff to camel casing further below).
+    regExpStringInner = "${regExpStringInner}_:\\.\\(\\)<>\\[\\]\{\}@&#\\?%";
   }
   // Match one or more of the characters specified above.
   String regExp = "[$regExpStringInner]+";
diff --git a/pkg/front_end/test/spell_checking_utils_test.dart b/pkg/front_end/test/spell_checking_utils_test.dart
index 202dc65..ed6bb7c 100644
--- a/pkg/front_end/test/spell_checking_utils_test.dart
+++ b/pkg/front_end/test/spell_checking_utils_test.dart
@@ -77,6 +77,9 @@
   expectSplit("foo?bar", false, ["foo?bar"], [0]);
   expectSplit("foo?bar", true, ["foo", "bar"], [0, 4]);
 
+  expectSplit("foo%bar", false, ["foo%bar"], [0]);
+  expectSplit("foo%bar", true, ["foo", "bar"], [0, 4]);
+
   print("OK");
 }
 
diff --git a/pkg/front_end/test/spelling_test_base.dart b/pkg/front_end/test/spelling_test_base.dart
index 274ac0e..ac96efe 100644
--- a/pkg/front_end/test/spelling_test_base.dart
+++ b/pkg/front_end/test/spelling_test_base.dart
@@ -28,7 +28,7 @@
 
 import 'spell_checking_utils.dart' as spell;
 
-abstract class Context extends ChainContext {
+abstract class SpellContext extends ChainContext {
   final List<Step> steps = const <Step>[
     const SpellTest(),
   ];
@@ -41,15 +41,17 @@
   }
 
   List<spell.Dictionaries> get dictionaries;
+
+  bool get onlyBlacklisted;
 }
 
-class SpellTest extends Step<TestDescription, TestDescription, Context> {
+class SpellTest extends Step<TestDescription, TestDescription, SpellContext> {
   const SpellTest();
 
   String get name => "spell test";
 
   Future<Result<TestDescription>> run(
-      TestDescription description, Context context) async {
+      TestDescription description, SpellContext context) async {
     File f = new File.fromUri(description.uri);
     List<int> rawBytes = f.readAsBytesSync();
 
@@ -90,6 +92,8 @@
               dictionaries: context.dictionaries);
           if (spellingResult.misspelledWords != null) {
             for (int i = 0; i < spellingResult.misspelledWords.length; i++) {
+              bool blacklisted = spellingResult.misspelledWordsBlacklisted[i];
+              if (context.onlyBlacklisted && !blacklisted) continue;
               int offset =
                   comment.offset + spellingResult.misspelledWordsOffset[i];
               String word = spellingResult.misspelledWords[i];
@@ -106,6 +110,8 @@
             dictionaries: context.dictionaries);
         if (spellingResult.misspelledWords != null) {
           for (int i = 0; i < spellingResult.misspelledWords.length; i++) {
+            bool blacklisted = spellingResult.misspelledWordsBlacklisted[i];
+            if (context.onlyBlacklisted && !blacklisted) continue;
             int offset = token.offset + spellingResult.misspelledWordsOffset[i];
             String word = spellingResult.misspelledWords[i];
             addErrorMessage(offset, word.length, "Misspelled word '$word'.");
diff --git a/pkg/front_end/test/spelling_test_external_targets.dart b/pkg/front_end/test/spelling_test_external_targets.dart
new file mode 100644
index 0000000..4f532a2
--- /dev/null
+++ b/pkg/front_end/test/spelling_test_external_targets.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async' show Future;
+
+import 'dart:io' show Directory, File, FileSystemEntity;
+
+import 'package:testing/testing.dart'
+    show Chain, FileBasedTestDescription, TestDescription, runMe;
+
+import 'spelling_test_base.dart' show SpellContext;
+
+import 'spell_checking_utils.dart' as spell;
+
+main([List<String> arguments = const []]) =>
+    runMe(arguments, createContext, configurationPath: "../testing.json");
+
+Future<SpellContext> createContext(
+    Chain suite, Map<String, String> environment) async {
+  return new SpellContextExternal();
+}
+
+class SpellContextExternal extends SpellContext {
+  @override
+  List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[];
+
+  @override
+  bool get onlyBlacklisted => true;
+
+  Stream<TestDescription> list(Chain suite) async* {
+    for (String subdir in const ["pkg/", "sdk/"]) {
+      Directory testRoot = new Directory.fromUri(suite.uri.resolve(subdir));
+      if (await testRoot.exists()) {
+        Stream<FileSystemEntity> files =
+            testRoot.list(recursive: true, followLinks: false);
+        await for (FileSystemEntity entity in files) {
+          if (entity is! File) continue;
+          String path = entity.uri.path;
+          if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
+          if (suite.pattern.any((RegExp r) => path.contains(r))) {
+            yield new FileBasedTestDescription(suite.uri, entity);
+          }
+        }
+      } else {
+        throw "${suite.uri} isn't a directory";
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/test/spelling_test_not_src_test.dart b/pkg/front_end/test/spelling_test_not_src_test.dart
index e1f675a..f281d14 100644
--- a/pkg/front_end/test/spelling_test_not_src_test.dart
+++ b/pkg/front_end/test/spelling_test_not_src_test.dart
@@ -11,18 +11,21 @@
 import 'spell_checking_utils.dart' as spell;
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
-Future<Context> createContext(
+Future<SpellContext> createContext(
     Chain suite, Map<String, String> environment) async {
-  return new ContextTest();
+  return new SpellContextTest();
 }
 
-class ContextTest extends Context {
+class SpellContextTest extends SpellContext {
   @override
   List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[
         spell.Dictionaries.common,
         spell.Dictionaries.cfeCode,
         spell.Dictionaries.cfeTests
       ];
+
+  @override
+  bool get onlyBlacklisted => false;
 }
diff --git a/pkg/front_end/test/spelling_test_src_test.dart b/pkg/front_end/test/spelling_test_src_test.dart
index 73cdc8d..12f5dcb 100644
--- a/pkg/front_end/test/spelling_test_src_test.dart
+++ b/pkg/front_end/test/spelling_test_src_test.dart
@@ -11,17 +11,20 @@
 import 'spell_checking_utils.dart' as spell;
 
 main([List<String> arguments = const []]) =>
-    runMe(arguments, createContext, "../testing.json");
+    runMe(arguments, createContext, configurationPath: "../testing.json");
 
-Future<Context> createContext(
+Future<SpellContext> createContext(
     Chain suite, Map<String, String> environment) async {
-  return new ContextSrc();
+  return new SpellContextSource();
 }
 
-class ContextSrc extends Context {
+class SpellContextSource extends SpellContext {
   @override
   List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[
         spell.Dictionaries.common,
         spell.Dictionaries.cfeCode
       ];
+
+  @override
+  bool get onlyBlacklisted => false;
 }
diff --git a/pkg/front_end/test/static_types/data/prefix_postfix.dart b/pkg/front_end/test/static_types/data/prefix_postfix.dart
new file mode 100644
index 0000000..a6b9d6e
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/prefix_postfix.dart
@@ -0,0 +1,131 @@
+// 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.
+
+num numTopLevel = /*int*/ 0;
+int intTopLevel = /*int*/ 0;
+dynamic dynamicTopLevel = /*int*/ 0;
+
+testTopLevel() {
+  /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ ++;
+  /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ --;
+  /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numTopLevel;
+  /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numTopLevel;
+
+  /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ ++;
+  /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ --;
+  /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intTopLevel;
+  /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intTopLevel;
+
+  /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ /*int*/ ++;
+  /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
+      /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++
+      /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
+  /*invoke: dynamic*/ /*int*/ --
+      /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
+}
+
+class Class {
+  num numInstance = /*int*/ 0;
+  int intInstance = /*int*/ 0;
+  dynamic dynamicInstance = /*int*/ 0;
+
+  testInstance() {
+    /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
+    /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
+    /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numInstance;
+    /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numInstance;
+
+    /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
+    /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
+    /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intInstance;
+    /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intInstance;
+
+    /*update: dynamic*/ /*dynamic*/ dynamicInstance
+        /*invoke: dynamic*/ /*int*/ ++;
+    /*update: dynamic*/ /*dynamic*/ dynamicInstance
+        /*invoke: dynamic*/ /*int*/ --;
+    /*invoke: dynamic*/ /*int*/ ++
+        /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+    /*invoke: dynamic*/ /*int*/ --
+        /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+  }
+}
+
+testInstanceOnClass(Class c) {
+  /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
+  /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
+  /*invoke: num*/ /*int*/ ++ /*Class*/ c. /*update: num*/ /*num*/ numInstance;
+  /*invoke: num*/ /*int*/ -- /*Class*/ c. /*update: num*/ /*num*/ numInstance;
+
+  /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
+  /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
+  /*invoke: int*/ /*int*/ ++ /*Class*/ c. /*update: int*/ /*int*/ intInstance;
+  /*invoke: int*/ /*int*/ -- /*Class*/ c. /*update: int*/ /*int*/ intInstance;
+
+  /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/ /*int*/ ++;
+  /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++ /*Class*/ c
+      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+  /*invoke: dynamic*/ /*int*/ -- /*Class*/ c
+      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+}
+
+testInstanceOnDynamic(dynamic c) {
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
+      /*invoke: dynamic*/ /*int*/ ++;
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
+      /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ numInstance;
+  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ numInstance;
+
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
+      /*invoke: dynamic*/ /*int*/ ++;
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
+      /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ intInstance;
+  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ intInstance;
+
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/ /*int*/ ++;
+  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+}
+
+main() {
+  /// ignore: unused_local_variable
+  num numLocal = /*int*/ 0;
+
+  /// ignore: unused_local_variable
+  int intLocal = /*int*/ 0;
+
+  /// ignore: unused_local_variable
+  dynamic dynamicLocal = /*int*/ 0;
+
+  /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ ++;
+  /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ --;
+  /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numLocal;
+  /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numLocal;
+
+  /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ ++;
+  /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ --;
+  /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intLocal;
+  /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intLocal;
+
+  /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ ++;
+  /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ --;
+  /*invoke: dynamic*/ /*int*/ ++ /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+  /*invoke: dynamic*/ /*int*/ -- /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+}
diff --git a/pkg/front_end/test/utils/io_utils.dart b/pkg/front_end/test/utils/io_utils.dart
new file mode 100644
index 0000000..7fdd197
--- /dev/null
+++ b/pkg/front_end/test/utils/io_utils.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'dart:io' show Directory, File, Platform, Process, ProcessResult;
+
+String computeRepoDir() {
+  ProcessResult result = Process.runSync(
+      'git', ['rev-parse', '--show-toplevel'],
+      runInShell: true,
+      workingDirectory: new File.fromUri(Platform.script).parent.path);
+  return (result.stdout as String).trim();
+}
+
+Uri computeRepoDirUri() {
+  String dirPath = computeRepoDir();
+  return new Directory(dirPath).uri;
+}
diff --git a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart b/pkg/front_end/test/utils/kernel_chain.dart
similarity index 88%
rename from pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
rename to pkg/front_end/test/utils/kernel_chain.dart
index 62bc602..fca8792 100644
--- a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
+++ b/pkg/front_end/test/utils/kernel_chain.dart
@@ -7,15 +7,38 @@
 import 'dart:async' show Future;
 
 import 'dart:io' show Directory, File, IOSink;
+import 'dart:io';
 
 import 'dart:typed_data' show Uint8List;
 
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+    show CompilerOptions, DiagnosticMessage;
+
+import 'package:front_end/src/base/processed_options.dart'
+    show ProcessedOptions;
+
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+    show computePlatformBinariesLocation;
+
+import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
+
+import 'package:front_end/src/fasta/fasta_codes.dart'
+    show templateInternalProblemUnhandled, templateUnspecified;
+
+import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyComponent;
+
+import 'package:front_end/src/fasta/messages.dart' show LocatedMessage;
+
+import 'package:front_end/src/fasta/resolve_input_uri.dart' show isWindows;
+
+import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
+
 import 'package:kernel/ast.dart' show Component, Library;
 
-import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
-
 import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
 
+import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
+
 import 'package:kernel/error_formatter.dart' show ErrorFormatter;
 
 import 'package:kernel/kernel.dart' show loadComponentFromBinary;
@@ -35,27 +58,6 @@
 import 'package:testing/testing.dart'
     show ChainContext, Expectation, ExpectationSet, Result, StdioProcess, Step;
 
-import '../../api_prototype/compiler_options.dart'
-    show CompilerOptions, DiagnosticMessage;
-
-import '../../base/processed_options.dart' show ProcessedOptions;
-
-import '../../compute_platform_binaries_location.dart'
-    show computePlatformBinariesLocation;
-
-import '../compiler_context.dart' show CompilerContext;
-
-import '../kernel/verifier.dart' show verifyComponent;
-
-import '../messages.dart' show LocatedMessage;
-
-import '../fasta_codes.dart'
-    show templateInternalProblemUnhandled, templateUnspecified;
-
-import '../resolve_input_uri.dart' show isWindows;
-
-import '../util/relativize.dart' show relativizeUri;
-
 final Uri platformBinariesLocation = computePlatformBinariesLocation();
 
 abstract class MatchContext implements ChainContext {
@@ -401,10 +403,32 @@
 }
 
 Future<String> runDiff(Uri expected, String actual) async {
-  StdioProcess process = await StdioProcess.run(
-      "git", <String>["diff", "--no-index", "-u", expected.toFilePath(), "-"],
-      input: actual, runInShell: true);
-  return process.output;
+  if (Platform.isWindows) {
+    // TODO(johnniwinther): Work-around for Windows. For some reason piping
+    // the actual result through stdin doesn't work; it shows a diff as if the
+    // actual result is the empty string.
+    Directory tempDirectory = Directory.systemTemp.createTempSync();
+    Uri uri = tempDirectory.uri.resolve('actual');
+    File file = new File.fromUri(uri)..writeAsStringSync(actual);
+    StdioProcess process = await StdioProcess.run(
+        "git",
+        <String>[
+          "diff",
+          "--no-index",
+          "-u",
+          expected.toFilePath(),
+          uri.toFilePath()
+        ],
+        runInShell: true);
+    file.deleteSync();
+    tempDirectory.deleteSync();
+    return process.output;
+  } else {
+    StdioProcess process = await StdioProcess.run(
+        "git", <String>["diff", "--no-index", "-u", expected.toFilePath(), "-"],
+        input: actual, runInShell: true);
+    return process.output;
+  }
 }
 
 Future<void> openWrite(Uri uri, f(IOSink sink)) async {
diff --git a/pkg/front_end/lib/src/fasta/testing/scanner_chain.dart b/pkg/front_end/test/utils/scanner_chain.dart
similarity index 80%
rename from pkg/front_end/lib/src/fasta/testing/scanner_chain.dart
rename to pkg/front_end/test/utils/scanner_chain.dart
index 151291f..3dbdd99 100644
--- a/pkg/front_end/lib/src/fasta/testing/scanner_chain.dart
+++ b/pkg/front_end/test/utils/scanner_chain.dart
@@ -4,11 +4,12 @@
 
 library fasta.testing.scanner_chain;
 
-import 'package:testing/testing.dart';
+import 'package:front_end/src/fasta/scanner.dart' show ScannerResult, scan;
 
-import '../scanner.dart';
+import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFile;
 
-import '../scanner/io.dart';
+import 'package:testing/testing.dart'
+    show ChainContext, Future, Result, Step, TestDescription;
 
 class ReadFile {
   final Uri uri;
diff --git a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart b/pkg/front_end/test/utils/validating_instrumentation.dart
similarity index 94%
rename from pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
rename to pkg/front_end/test/utils/validating_instrumentation.dart
index 8c96c60..afdda22 100644
--- a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
+++ b/pkg/front_end/test/utils/validating_instrumentation.dart
@@ -8,19 +8,22 @@
 
 import 'dart:io' show File;
 
-import '../../base/instrumentation.dart';
+import 'package:front_end/src/base/instrumentation.dart'
+    show Instrumentation, InstrumentationValue;
 
-import '../../scanner/token.dart' as analyzer;
+import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
-import '../compiler_context.dart' show CompilerContext;
+import 'package:front_end/src/fasta/messages.dart'
+    show noLength, templateUnspecified;
 
-import '../messages.dart' show noLength, templateUnspecified;
+import 'package:front_end/src/fasta/scanner.dart'
+    show ScannerResult, Token, scan;
 
-import '../scanner.dart' show ScannerResult, Token, scan;
+import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFile;
 
-import '../scanner/io.dart' show readBytesFromFile;
+import 'package:front_end/src/fasta/severity.dart' show Severity;
 
-import '../severity.dart' show Severity;
+import 'package:front_end/src/scanner/token.dart' as analyzer show Token;
 
 /// Implementation of [Instrumentation] which checks property/value pairs
 /// against expectations encoded in source files using "/*@...*/" comments.
diff --git a/pkg/front_end/test/whole_program_test.dart b/pkg/front_end/test/whole_program_test.dart
index 717e20c..f9c2d2f 100644
--- a/pkg/front_end/test/whole_program_test.dart
+++ b/pkg/front_end/test/whole_program_test.dart
@@ -52,7 +52,7 @@
 
 Future runCompiler(Uri input, Uri output) async {
   final Uri platformDill = computePlatformBinariesLocation(forceBuildDir: true)
-      .resolve("vm_platform.dill");
+      .resolve("vm_platform_strong.dill");
 
   final List<String> arguments = <String>[
     '--packages=${packagesFile.toFilePath()}',
diff --git a/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
index 4d0bbb7..a38c415 100644
--- a/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
@@ -6,4 +6,4 @@
   ^
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
-  return main::hasBound<#lib1::debugExpr::T>();
+  return main::hasBound<#lib1::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
index 4d0bbb7..a38c415 100644
--- a/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
@@ -6,4 +6,4 @@
   ^
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
-  return main::hasBound<#lib1::debugExpr::T>();
+  return main::hasBound<#lib1::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
index dfc583e..6cb5b78 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
@@ -1,4 +1,4 @@
 Errors: {
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
-  return x is main::A::debugExpr::T;
+  return x is main::A::debugExpr::T*;
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
index 1a951e3..5b54940 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
@@ -1,4 +1,4 @@
 Errors: {
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
-  return main::id<main::A::debugExpr::T>(x as{TypeError} main::A::debugExpr::T);
+  return main::id<main::A::debugExpr::T*>(x as{TypeError} main::A::debugExpr::T*);
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
index 9a35069..82ea2ad 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
@@ -7,5 +7,5 @@
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
   return () → dart.core::Null* {
-    main::A::debugExpr::T k = let final<BottomType> #t1 = invalid-expression "org-dartlang-debug:synthetic_debug_expression:2:13: Error: A value of type 'A<dynamic>' can't be assigned to a variable of type 'T'.\n - 'A' is from 'pkg/front_end/testcases/expression/main.dart'.\nTry changing the type of the left hand side, or casting the right hand side to 'T'.\n  T k = new A();\n            ^" in new main::A::•<dynamic>() as{TypeError} <BottomType>;
+    main::A::debugExpr::T* k = let final<BottomType> #t1 = invalid-expression "org-dartlang-debug:synthetic_debug_expression:2:13: Error: A value of type 'A<dynamic>' can't be assigned to a variable of type 'T'.\n - 'A' is from 'pkg/front_end/testcases/expression/main.dart'.\nTry changing the type of the left hand side, or casting the right hand side to 'T'.\n  T k = new A();\n            ^" in new main::A::•<dynamic>() as{TypeError} <BottomType>;
   };
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
index 8c299a7..140cb36 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
@@ -2,6 +2,6 @@
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
   return () → dart.core::Null* {
-    main::A::debugExpr::T k = null;
-    k = main::id<main::A::debugExpr::T>(k);
+    main::A::debugExpr::T* k = null;
+    k = main::id<main::A::debugExpr::T*>(k);
   };
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
index 87f7a81..6ae7542 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
@@ -1,4 +1,4 @@
 Errors: {
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
-  return new main::A::•<main::A::debugExpr::T>();
+  return new main::A::•<main::A::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
index 4a2c0ec..ad817cd 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
@@ -2,5 +2,5 @@
 }
 method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
   return () → dart.core::Null* {
-    main::A::debugExpr::T x = null;
+    main::A::debugExpr::T* x = null;
   };
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
index dfcdbe8..86ff6e6 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
@@ -14,27 +14,41 @@
 }
 extension Extension on self::Class* {
   method readGetter = self::Extension|readGetter;
+  tearoff readGetter = self::Extension|get#readGetter;
   method writeSetterRequired = self::Extension|writeSetterRequired;
+  tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
   method writeSetterOptional = self::Extension|writeSetterOptional;
+  tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
   method writeSetterNamed = self::Extension|writeSetterNamed;
+  tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
   get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
   get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
   get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
   get property = self::Extension|get#property;
   method invocations = self::Extension|invocations;
+  tearoff invocations = self::Extension|get#invocations;
   method tearOffs = self::Extension|tearOffs;
+  tearoff tearOffs = self::Extension|get#tearOffs;
   method getterCalls = self::Extension|getterCalls;
+  tearoff getterCalls = self::Extension|get#getterCalls;
   set property = self::Extension|set#property;
 }
 extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
   method readGetter = self::GenericExtension|readGetter;
+  tearoff readGetter = self::GenericExtension|get#readGetter;
   method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+  tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
   method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+  tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
   method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+  tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
   method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+  tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
   method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+  tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
   method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+  tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
   get property = self::GenericExtension|get#property;
   get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -44,18 +58,29 @@
   get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
   get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
   method invocations = self::GenericExtension|invocations;
+  tearoff invocations = self::GenericExtension|get#invocations;
   method tearOffs = self::GenericExtension|tearOffs;
+  tearoff tearOffs = self::GenericExtension|get#tearOffs;
   method getterCalls = self::GenericExtension|getterCalls;
+  tearoff getterCalls = self::GenericExtension|get#getterCalls;
   set property = self::GenericExtension|set#property;
 }
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|readGetter(#this);
 static method Extension|readGetter(final self::Class* #this) → dynamic
   ;
 static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic
   ;
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
 static method Extension|writeSetterOptional(final self::Class* #this, [dynamic value]) → dynamic
   ;
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+  return ([dynamic value = null]) → dynamic => self::Extension|writeSetterOptional(#this, value);
 static method Extension|writeSetterNamed(final self::Class* #this, {dynamic value}) → dynamic
   ;
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
+  return ({dynamic value = null}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
 static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
   ;
 static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
@@ -70,47 +95,73 @@
   ;
 static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic
   ;
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
 static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic
   ;
 static method Extension|getterCalls(final self::Class* #this, dynamic value) → dynamic
   ;
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T*
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T*
   ;
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+  return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic
   ;
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this, [self::GenericExtension|writeSetterOptional::#T* value]) → dynamic
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+  return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this, [self::GenericExtension|writeSetterOptional::T* value]) → dynamic
   ;
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this, {self::GenericExtension|writeSetterNamed::#T* value}) → dynamic
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+  return ([self::GenericExtension|get#writeSetterOptional::T* value = null]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this, {self::GenericExtension|writeSetterNamed::T* value}) → dynamic
   ;
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+  return ({self::GenericExtension|get#writeSetterNamed::T* value = null}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic
   ;
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this, [self::GenericExtension|genericWriteSetterOptional::S value]) → dynamic
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this, [self::GenericExtension|genericWriteSetterOptional::S* value]) → dynamic
   ;
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this, {self::GenericExtension|genericWriteSetterNamed::S value}) → dynamic
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = null]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = null}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this, {self::GenericExtension|genericWriteSetterNamed::S* value}) → dynamic
   ;
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
   ;
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → void
   ;
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
   ;
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
   ;
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic
   ;
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic
   ;
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic
   ;
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
index eff6825..a652a17 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
@@ -16,27 +16,41 @@
 }
 extension Extension on self::Class* {
   method readGetter = self::Extension|readGetter;
+  tearoff readGetter = self::Extension|get#readGetter;
   method writeSetterRequired = self::Extension|writeSetterRequired;
+  tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
   method writeSetterOptional = self::Extension|writeSetterOptional;
+  tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
   method writeSetterNamed = self::Extension|writeSetterNamed;
+  tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
   get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
   get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
   get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
   get property = self::Extension|get#property;
   method invocations = self::Extension|invocations;
+  tearoff invocations = self::Extension|get#invocations;
   method tearOffs = self::Extension|tearOffs;
+  tearoff tearOffs = self::Extension|get#tearOffs;
   method getterCalls = self::Extension|getterCalls;
+  tearoff getterCalls = self::Extension|get#getterCalls;
   set property = self::Extension|set#property;
 }
 extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
   method readGetter = self::GenericExtension|readGetter;
+  tearoff readGetter = self::GenericExtension|get#readGetter;
   method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+  tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
   method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+  tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
   method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+  tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
   method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+  tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
   method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+  tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
   method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+  tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
   get property = self::GenericExtension|get#property;
   get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -46,34 +60,47 @@
   get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
   get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
   method invocations = self::GenericExtension|invocations;
+  tearoff invocations = self::GenericExtension|get#invocations;
   method tearOffs = self::GenericExtension|tearOffs;
+  tearoff tearOffs = self::GenericExtension|get#tearOffs;
   method getterCalls = self::GenericExtension|getterCalls;
+  tearoff getterCalls = self::GenericExtension|get#getterCalls;
   set property = self::GenericExtension|set#property;
 }
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|readGetter(#this);
 static method Extension|readGetter(final self::Class* #this) → dynamic {
   return self::Extension|get#property(#this);
 }
 static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic {
   self::Extension|set#property(#this, value);
 }
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
 static method Extension|writeSetterOptional(final self::Class* #this = #C1, [dynamic value = #C1]) → dynamic {
   self::Extension|set#property(#this, value);
 }
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+  return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
 static method Extension|writeSetterNamed(final self::Class* #this = #C1, {dynamic value = #C1}) → dynamic {
   self::Extension|set#property(#this, value);
 }
-static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
-  return () → dynamic => self::Extension|readGetter(#this);
-static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
-  return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
-static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
-  return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
-static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
   return ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
+  return self::Extension|get#readGetter(#this);
+static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterRequired(#this);
+static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterOptional(#this);
+static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterNamed(#this);
 static method Extension|get#property(final self::Class* #this) → dynamic
   return #this.{self::Class::field};
-static method Extension|set#property(final self::Class* #this, dynamic value) → void {
+static method Extension|set#property(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
   #this.{self::Class::field} = value;
+  return #t1;
 }
 static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic {
   self::Extension|readGetter(#this);
@@ -83,15 +110,19 @@
   self::Extension|writeSetterNamed(#this);
   self::Extension|writeSetterNamed(#this, value: value);
 }
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
 static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic {
-  () →* dynamic tearOffNoArgs = () → dynamic => self::Extension|readGetter(#this);
+  () →* dynamic tearOffNoArgs = self::Extension|get#readGetter(#this);
   tearOffNoArgs.call();
-  (dynamic) →* dynamic tearOffRequired = (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
+  (dynamic) →* dynamic tearOffRequired = self::Extension|get#writeSetterRequired(#this);
   tearOffRequired.call(value);
-  ([dynamic]) →* dynamic tearOffOptional = ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
+  ([dynamic]) →* dynamic tearOffOptional = self::Extension|get#writeSetterOptional(#this);
   tearOffOptional.call();
   tearOffOptional.call(value);
-  ({value: dynamic}) →* dynamic tearOffNamed = ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+  ({value: dynamic}) →* dynamic tearOffNamed = self::Extension|get#writeSetterNamed(#this);
   tearOffNamed.call();
   tearOffNamed.call(value: value);
 }
@@ -103,107 +134,131 @@
   self::Extension|get#tearOffGetterNamed(#this).call();
   self::Extension|get#tearOffGetterNamed(#this).call(value: value);
 }
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T* {
-  return self::GenericExtension|get#property<self::GenericExtension|readGetter::#T*>(#this);
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T* {
+  return self::GenericExtension|get#property<self::GenericExtension|readGetter::T*>(#this);
 }
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+  return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::T*>(#this, value);
 }
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::#T* value = #C1]) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+  return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::T* value = #C1]) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::T*>(#this, value);
 }
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::#T* value = #C1}) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+  return ([self::GenericExtension|get#writeSetterOptional::T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::T* value = #C1}) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+  return ({self::GenericExtension|get#writeSetterNamed::T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S value = #C1]) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S* value = #C1]) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S value = #C1}) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S* value = #C1}) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::T*>(#this, value);
 }
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
   return #this.{self::GenericClass::field};
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void {
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → self::GenericExtension|set#property::T* {
+  final self::GenericExtension|set#property::T* #t2 = value;
   #this.{self::GenericClass::field} = value;
+  return #t2;
 }
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
-  return () → self::GenericExtension|get#tearOffGetterNoArgs::#T* => self::GenericExtension|readGetter<self::GenericExtension|get#tearOffGetterNoArgs::#T*>(#this);
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
-  return (self::GenericExtension|get#tearOffGetterRequired::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
-  return ([self::GenericExtension|get#tearOffGetterOptional::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
-  return ({self::GenericExtension|get#tearOffGetterNamed::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::#T*>(#this, value: value);
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericRequired::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericOptional::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericNamed::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::#T*, S>(#this, value: value);
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic {
-  self::GenericExtension|readGetter<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::#T*>(#this, value);
-  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this, value);
-  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this, value: value);
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
+  return self::GenericExtension|get#readGetter<self::GenericExtension|get#tearOffGetterNoArgs::T*>(#this);
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::T*>(#this);
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic {
+  self::GenericExtension|readGetter<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::T*>(#this, value);
+  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this, value);
+  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this, value: value);
 }
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic {
-  () →* self::GenericExtension|tearOffs::#T* tearOffNoArgs = () → self::GenericExtension|tearOffs::#T* => self::GenericExtension|readGetter<self::GenericExtension|tearOffs::#T*>(#this);
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic {
+  () →* self::GenericExtension|tearOffs::T* tearOffNoArgs = self::GenericExtension|get#readGetter<self::GenericExtension|tearOffs::T*>(#this);
   tearOffNoArgs.call();
-  (self::GenericExtension|tearOffs::#T*) →* dynamic tearOffRequired = (self::GenericExtension|tearOffs::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|tearOffs::#T*>(#this, value);
+  (self::GenericExtension|tearOffs::T*) →* dynamic tearOffRequired = self::GenericExtension|get#writeSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
   tearOffRequired.call(value);
-  ([self::GenericExtension|tearOffs::#T*]) →* dynamic tearOffOptional = ([self::GenericExtension|tearOffs::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|tearOffs::#T*>(#this, value);
+  ([self::GenericExtension|tearOffs::T*]) →* dynamic tearOffOptional = self::GenericExtension|get#writeSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
   tearOffOptional.call();
   tearOffOptional.call(value);
-  ({value: self::GenericExtension|tearOffs::#T*}) →* dynamic tearOffNamed = ({self::GenericExtension|tearOffs::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|tearOffs::#T*>(#this, value: value);
+  ({value: self::GenericExtension|tearOffs::T*}) →* dynamic tearOffNamed = self::GenericExtension|get#writeSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
   tearOffNamed.call();
   tearOffNamed.call(value: value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S) →* dynamic genericTearOffRequired = <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|tearOffs::#T*, S>(#this, value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::#T*>(value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S]) →* dynamic genericTearOffOptional = <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|tearOffs::#T*, S>(#this, value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>(value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>({value: S}) →* dynamic genericTearOffNamed = <S extends self::GenericExtension|tearOffs::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|tearOffs::#T*, S>(#this, value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>(value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>(S*) →* dynamic genericTearOffRequired = self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::T*>(value);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>([S*]) →* dynamic genericTearOffOptional = self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>(value);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>({value: S*}) →* dynamic genericTearOffNamed = self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>(value: value);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
 }
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic {
-  self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value: value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value: value);
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic {
+  self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value: value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value: value);
 }
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
index eff6825..a652a17 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
@@ -16,27 +16,41 @@
 }
 extension Extension on self::Class* {
   method readGetter = self::Extension|readGetter;
+  tearoff readGetter = self::Extension|get#readGetter;
   method writeSetterRequired = self::Extension|writeSetterRequired;
+  tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
   method writeSetterOptional = self::Extension|writeSetterOptional;
+  tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
   method writeSetterNamed = self::Extension|writeSetterNamed;
+  tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
   get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
   get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
   get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
   get property = self::Extension|get#property;
   method invocations = self::Extension|invocations;
+  tearoff invocations = self::Extension|get#invocations;
   method tearOffs = self::Extension|tearOffs;
+  tearoff tearOffs = self::Extension|get#tearOffs;
   method getterCalls = self::Extension|getterCalls;
+  tearoff getterCalls = self::Extension|get#getterCalls;
   set property = self::Extension|set#property;
 }
 extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
   method readGetter = self::GenericExtension|readGetter;
+  tearoff readGetter = self::GenericExtension|get#readGetter;
   method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+  tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
   method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+  tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
   method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+  tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
   method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+  tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
   method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+  tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
   method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+  tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
   get property = self::GenericExtension|get#property;
   get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
   get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -46,34 +60,47 @@
   get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
   get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
   method invocations = self::GenericExtension|invocations;
+  tearoff invocations = self::GenericExtension|get#invocations;
   method tearOffs = self::GenericExtension|tearOffs;
+  tearoff tearOffs = self::GenericExtension|get#tearOffs;
   method getterCalls = self::GenericExtension|getterCalls;
+  tearoff getterCalls = self::GenericExtension|get#getterCalls;
   set property = self::GenericExtension|set#property;
 }
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|readGetter(#this);
 static method Extension|readGetter(final self::Class* #this) → dynamic {
   return self::Extension|get#property(#this);
 }
 static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic {
   self::Extension|set#property(#this, value);
 }
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
 static method Extension|writeSetterOptional(final self::Class* #this = #C1, [dynamic value = #C1]) → dynamic {
   self::Extension|set#property(#this, value);
 }
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+  return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
 static method Extension|writeSetterNamed(final self::Class* #this = #C1, {dynamic value = #C1}) → dynamic {
   self::Extension|set#property(#this, value);
 }
-static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
-  return () → dynamic => self::Extension|readGetter(#this);
-static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
-  return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
-static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
-  return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
-static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
   return ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
+  return self::Extension|get#readGetter(#this);
+static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterRequired(#this);
+static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterOptional(#this);
+static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+  return self::Extension|get#writeSetterNamed(#this);
 static method Extension|get#property(final self::Class* #this) → dynamic
   return #this.{self::Class::field};
-static method Extension|set#property(final self::Class* #this, dynamic value) → void {
+static method Extension|set#property(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
   #this.{self::Class::field} = value;
+  return #t1;
 }
 static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic {
   self::Extension|readGetter(#this);
@@ -83,15 +110,19 @@
   self::Extension|writeSetterNamed(#this);
   self::Extension|writeSetterNamed(#this, value: value);
 }
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
 static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic {
-  () →* dynamic tearOffNoArgs = () → dynamic => self::Extension|readGetter(#this);
+  () →* dynamic tearOffNoArgs = self::Extension|get#readGetter(#this);
   tearOffNoArgs.call();
-  (dynamic) →* dynamic tearOffRequired = (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
+  (dynamic) →* dynamic tearOffRequired = self::Extension|get#writeSetterRequired(#this);
   tearOffRequired.call(value);
-  ([dynamic]) →* dynamic tearOffOptional = ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
+  ([dynamic]) →* dynamic tearOffOptional = self::Extension|get#writeSetterOptional(#this);
   tearOffOptional.call();
   tearOffOptional.call(value);
-  ({value: dynamic}) →* dynamic tearOffNamed = ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+  ({value: dynamic}) →* dynamic tearOffNamed = self::Extension|get#writeSetterNamed(#this);
   tearOffNamed.call();
   tearOffNamed.call(value: value);
 }
@@ -103,107 +134,131 @@
   self::Extension|get#tearOffGetterNamed(#this).call();
   self::Extension|get#tearOffGetterNamed(#this).call(value: value);
 }
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T* {
-  return self::GenericExtension|get#property<self::GenericExtension|readGetter::#T*>(#this);
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T* {
+  return self::GenericExtension|get#property<self::GenericExtension|readGetter::T*>(#this);
 }
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+  return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::T*>(#this, value);
 }
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::#T* value = #C1]) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+  return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::T* value = #C1]) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::T*>(#this, value);
 }
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::#T* value = #C1}) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+  return ([self::GenericExtension|get#writeSetterOptional::T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::T* value = #C1}) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+  return ({self::GenericExtension|get#writeSetterNamed::T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S value = #C1]) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S* value = #C1]) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::T*>(#this, value);
 }
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S value = #C1}) → dynamic {
-  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+  return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S* value = #C1}) → dynamic {
+  self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::T*>(#this, value);
 }
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
   return #this.{self::GenericClass::field};
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void {
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → self::GenericExtension|set#property::T* {
+  final self::GenericExtension|set#property::T* #t2 = value;
   #this.{self::GenericClass::field} = value;
+  return #t2;
 }
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
-  return () → self::GenericExtension|get#tearOffGetterNoArgs::#T* => self::GenericExtension|readGetter<self::GenericExtension|get#tearOffGetterNoArgs::#T*>(#this);
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
-  return (self::GenericExtension|get#tearOffGetterRequired::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
-  return ([self::GenericExtension|get#tearOffGetterOptional::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
-  return ({self::GenericExtension|get#tearOffGetterNamed::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::#T*>(#this, value: value);
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericRequired::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericOptional::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
-  return <S extends self::GenericExtension|get#tearOffGetterGenericNamed::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::#T*, S>(#this, value: value);
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic {
-  self::GenericExtension|readGetter<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::#T*>(#this, value);
-  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this, value);
-  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this);
-  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this, value: value);
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
+  return self::GenericExtension|get#readGetter<self::GenericExtension|get#tearOffGetterNoArgs::T*>(#this);
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
+  return self::GenericExtension|get#writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
+  return self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::T*>(#this);
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic {
+  self::GenericExtension|readGetter<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::T*>(#this, value);
+  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this, value);
+  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this);
+  self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this, value: value);
 }
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic {
-  () →* self::GenericExtension|tearOffs::#T* tearOffNoArgs = () → self::GenericExtension|tearOffs::#T* => self::GenericExtension|readGetter<self::GenericExtension|tearOffs::#T*>(#this);
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic {
+  () →* self::GenericExtension|tearOffs::T* tearOffNoArgs = self::GenericExtension|get#readGetter<self::GenericExtension|tearOffs::T*>(#this);
   tearOffNoArgs.call();
-  (self::GenericExtension|tearOffs::#T*) →* dynamic tearOffRequired = (self::GenericExtension|tearOffs::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|tearOffs::#T*>(#this, value);
+  (self::GenericExtension|tearOffs::T*) →* dynamic tearOffRequired = self::GenericExtension|get#writeSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
   tearOffRequired.call(value);
-  ([self::GenericExtension|tearOffs::#T*]) →* dynamic tearOffOptional = ([self::GenericExtension|tearOffs::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|tearOffs::#T*>(#this, value);
+  ([self::GenericExtension|tearOffs::T*]) →* dynamic tearOffOptional = self::GenericExtension|get#writeSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
   tearOffOptional.call();
   tearOffOptional.call(value);
-  ({value: self::GenericExtension|tearOffs::#T*}) →* dynamic tearOffNamed = ({self::GenericExtension|tearOffs::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|tearOffs::#T*>(#this, value: value);
+  ({value: self::GenericExtension|tearOffs::T*}) →* dynamic tearOffNamed = self::GenericExtension|get#writeSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
   tearOffNamed.call();
   tearOffNamed.call(value: value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S) →* dynamic genericTearOffRequired = <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|tearOffs::#T*, S>(#this, value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::#T*>(value);
-  genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S]) →* dynamic genericTearOffOptional = <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|tearOffs::#T*, S>(#this, value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>();
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>(value);
-  genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
-  <S extends self::GenericExtension|tearOffs::#T* = dynamic>({value: S}) →* dynamic genericTearOffNamed = <S extends self::GenericExtension|tearOffs::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|tearOffs::#T*, S>(#this, value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>();
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>(value: value);
-  genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>(S*) →* dynamic genericTearOffRequired = self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::T*>(value);
+  genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>([S*]) →* dynamic genericTearOffOptional = self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>();
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>(value);
+  genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+  <S extends self::GenericExtension|tearOffs::T* = dynamic>({value: S*}) →* dynamic genericTearOffNamed = self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>();
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>(value: value);
+  genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
 }
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic {
-  self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
-  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
-  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value: value);
-  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value: value);
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic {
+  self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+  self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+  self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value: value);
+  self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value: value);
 }
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+  return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
index 5a1e9ab..f704ade 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
@@ -29,9 +29,13 @@
   static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
   static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
   method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+  tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
   method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+  tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
   method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+  tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
   method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+  tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
   static set property = set self::Extension|property;
 }
 static field dynamic Extension|field;
@@ -75,13 +79,21 @@
   ;
 static method Extension|getterCallsFromStaticContext(core::int* value) → dynamic
   ;
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic
   ;
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic
   ;
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic
   ;
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic
   ;
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
index 1d70dc7..a7051b9 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
@@ -30,9 +30,13 @@
   static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
   static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
   method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+  tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
   method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+  tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
   method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+  tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
   method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+  tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
   static set property = set self::Extension|property;
 }
 static field dynamic Extension|field;
@@ -141,25 +145,27 @@
   self::Extension|tearOffGetterGenericNamed.call(value: value);
   self::Extension|tearOffGetterGenericNamed.call<core::int*>(value: value);
 }
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic {
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic {
   self::Extension|readGetter();
   self::Extension|writeSetterRequired(value);
   self::Extension|writeSetterOptional();
   self::Extension|writeSetterOptional(value);
   self::Extension|writeSetterNamed();
   self::Extension|writeSetterNamed(value: value);
-  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
-  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
+  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
+  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
   self::Extension|genericWriteSetterOptional<dynamic>();
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>();
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>();
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
   self::Extension|genericWriteSetterNamed<dynamic>();
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>();
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>();
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
 }
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic {
   () →* dynamic tearOffNoArgs = #C2;
   tearOffNoArgs.call();
   (dynamic) →* dynamic tearOffRequired = #C3;
@@ -171,24 +177,28 @@
   tearOffNamed.call();
   tearOffNamed.call(value: value);
   <S extends core::Object* = dynamic>(self::Extension|genericWriteSetterRequired::S*) →* dynamic tearOffGenericRequired = #C6;
-  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
-  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
   <S extends core::Object* = dynamic>([self::Extension|genericWriteSetterOptional::S*]) →* dynamic tearOffGenericOptional = #C7;
   tearOffGenericOptional.call<dynamic>();
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>();
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>();
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
   <S extends core::Object* = dynamic>({value: self::Extension|genericWriteSetterNamed::S*}) →* dynamic tearOffGenericNamed = #C8;
   tearOffGenericNamed.call<dynamic>();
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>();
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>();
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
 }
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic {
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic {
   self::Extension|field = self::Extension|property;
   self::Extension|property = self::Extension|field;
 }
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic {
   self::Extension|tearOffGetterNoArgs.call();
   self::Extension|tearOffGetterRequired.call(value);
   self::Extension|tearOffGetterOptional.call();
@@ -196,16 +206,18 @@
   self::Extension|tearOffGetterNamed.call();
   self::Extension|tearOffGetterNamed.call(value: value);
   self::Extension|tearOffGetterGenericRequired.call(value);
-  self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+  self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
   self::Extension|tearOffGetterGenericOptional.call();
-  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>();
   self::Extension|tearOffGetterGenericOptional.call(value);
-  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
   self::Extension|tearOffGetterGenericNamed.call();
-  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>();
   self::Extension|tearOffGetterGenericNamed.call(value: value);
-  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>(value: value);
+  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>(value: value);
 }
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
index 1d70dc7..a7051b9 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
@@ -30,9 +30,13 @@
   static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
   static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
   method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+  tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
   method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+  tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
   method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+  tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
   method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+  tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
   static set property = set self::Extension|property;
 }
 static field dynamic Extension|field;
@@ -141,25 +145,27 @@
   self::Extension|tearOffGetterGenericNamed.call(value: value);
   self::Extension|tearOffGetterGenericNamed.call<core::int*>(value: value);
 }
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic {
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic {
   self::Extension|readGetter();
   self::Extension|writeSetterRequired(value);
   self::Extension|writeSetterOptional();
   self::Extension|writeSetterOptional(value);
   self::Extension|writeSetterNamed();
   self::Extension|writeSetterNamed(value: value);
-  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
-  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
+  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
+  self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
   self::Extension|genericWriteSetterOptional<dynamic>();
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>();
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
-  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>();
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
+  self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
   self::Extension|genericWriteSetterNamed<dynamic>();
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>();
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
-  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>();
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
+  self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
 }
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic {
   () →* dynamic tearOffNoArgs = #C2;
   tearOffNoArgs.call();
   (dynamic) →* dynamic tearOffRequired = #C3;
@@ -171,24 +177,28 @@
   tearOffNamed.call();
   tearOffNamed.call(value: value);
   <S extends core::Object* = dynamic>(self::Extension|genericWriteSetterRequired::S*) →* dynamic tearOffGenericRequired = #C6;
-  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
-  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+  tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
   <S extends core::Object* = dynamic>([self::Extension|genericWriteSetterOptional::S*]) →* dynamic tearOffGenericOptional = #C7;
   tearOffGenericOptional.call<dynamic>();
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>();
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
-  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>();
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+  tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
   <S extends core::Object* = dynamic>({value: self::Extension|genericWriteSetterNamed::S*}) →* dynamic tearOffGenericNamed = #C8;
   tearOffGenericNamed.call<dynamic>();
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>();
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
-  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>();
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
+  tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
 }
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic {
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic {
   self::Extension|field = self::Extension|property;
   self::Extension|property = self::Extension|field;
 }
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic {
   self::Extension|tearOffGetterNoArgs.call();
   self::Extension|tearOffGetterRequired.call(value);
   self::Extension|tearOffGetterOptional.call();
@@ -196,16 +206,18 @@
   self::Extension|tearOffGetterNamed.call();
   self::Extension|tearOffGetterNamed.call(value: value);
   self::Extension|tearOffGetterGenericRequired.call(value);
-  self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+  self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
   self::Extension|tearOffGetterGenericOptional.call();
-  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>();
   self::Extension|tearOffGetterGenericOptional.call(value);
-  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+  self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
   self::Extension|tearOffGetterGenericNamed.call();
-  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>();
   self::Extension|tearOffGetterGenericNamed.call(value: value);
-  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>(value: value);
+  self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>(value: value);
 }
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+  return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart b/pkg/front_end/testcases/extensions/explicit_extension_access.dart
new file mode 100644
index 0000000..d030faf
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {
+  int field1 = 42;
+  int field2 = 87;
+}
+
+extension Extension1 on Class {
+  int get field => field1;
+  void set field(int value) {
+    field1 = value;
+  }
+  int method() => field1;
+  int genericMethod<T extends num>(T t) => field1 + t;
+}
+
+extension Extension2 on Class {
+  int get field => field2;
+  void set field(int value) {
+    field2 = value;
+  }
+  int method() => field2;
+  int genericMethod<T extends num>(T t) => field2 + t;
+}
+
+main() {
+  Class c = new Class();
+  expect(42, Extension1(c).field);
+  expect(87, Extension2(c).field);
+  expect(42, Extension1(c).method());
+  expect(87, Extension2(c).method());
+  var tearOff1 = Extension1(c).method;
+  var tearOff2 = Extension2(c).method;
+  expect(42, tearOff1());
+  expect(87, tearOff2());
+  expect(52, Extension1(c).genericMethod(10));
+  expect(97, Extension2(c).genericMethod(10));
+  expect(52, Extension1(c).genericMethod<num>(10));
+  expect(97, Extension2(c).genericMethod<num>(10));
+  var genericTearOff1 = Extension1(c).genericMethod;
+  var genericTearOff2 = Extension2(c).genericMethod;
+  expect(52, genericTearOff1(10));
+  expect(97, genericTearOff2(10));
+  expect(52, genericTearOff1<num>(10));
+  expect(97, genericTearOff2<num>(10));
+  expect(23, Extension1(c).field = 23);
+  expect(67, Extension2(c).field = 67);
+  expect(23, Extension1(c).field);
+  expect(67, Extension2(c).field);
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect
new file mode 100644
index 0000000..cf66bc6
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect
@@ -0,0 +1,54 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int* field1;
+  field core::int* field2;
+  synthetic constructor •() → self::Class*
+    ;
+}
+extension Extension1 on self::Class* {
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+  ;
+static method Extension1|set#field(final self::Class* #this, core::int* value) → void
+  ;
+static method Extension1|method(final self::Class* #this) → core::int*
+  ;
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+  ;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+  ;
+static method Extension2|set#field(final self::Class* #this, core::int* value) → void
+  ;
+static method Extension2|method(final self::Class* #this) → core::int*
+  ;
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+  ;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect
new file mode 100644
index 0000000..70f01be
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect
@@ -0,0 +1,87 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int* field1 = 42;
+  field core::int* field2 = 87;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension1 on self::Class* {
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+  return #this.{self::Class::field1};
+static method Extension1|set#field(final self::Class* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
+  #this.{self::Class::field1} = value;
+  return #t1;
+}
+static method Extension1|method(final self::Class* #this) → core::int*
+  return #this.{self::Class::field1};
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+  return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+  return #this.{self::Class::field2};
+static method Extension2|set#field(final self::Class* #this, core::int* value) → core::int* {
+  final core::int* #t2 = value;
+  #this.{self::Class::field2} = value;
+  return #t2;
+}
+static method Extension2|method(final self::Class* #this) → core::int*
+  return #this.{self::Class::field2};
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+  return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+  self::Class* c = new self::Class::•();
+  self::expect(42, self::Extension1|get#field(c));
+  self::expect(87, self::Extension2|get#field(c));
+  self::expect(42, self::Extension1|method(c));
+  self::expect(87, self::Extension2|method(c));
+  () →* core::int* tearOff1 = self::Extension1|get#method(c);
+  () →* core::int* tearOff2 = self::Extension2|get#method(c);
+  self::expect(42, tearOff1.call());
+  self::expect(87, tearOff2.call());
+  self::expect(52, self::Extension1|genericMethod<core::int*>(c, 10));
+  self::expect(97, self::Extension2|genericMethod<core::int*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::num*>(c, 10));
+  self::expect(97, self::Extension2|genericMethod<core::num*>(c, 10));
+  <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c);
+  <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff2 = self::Extension2|get#genericMethod(c);
+  self::expect(52, genericTearOff1.call<core::int*>(10));
+  self::expect(97, genericTearOff2.call<core::int*>(10));
+  self::expect(52, genericTearOff1.call<core::num*>(10));
+  self::expect(97, genericTearOff2.call<core::num*>(10));
+  self::expect(23, self::Extension1|set#field(c, 23));
+  self::expect(67, self::Extension2|set#field(c, 67));
+  self::expect(23, self::Extension1|get#field(c));
+  self::expect(67, self::Extension2|get#field(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..70f01be
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect
@@ -0,0 +1,87 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int* field1 = 42;
+  field core::int* field2 = 87;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension1 on self::Class* {
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+  return #this.{self::Class::field1};
+static method Extension1|set#field(final self::Class* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
+  #this.{self::Class::field1} = value;
+  return #t1;
+}
+static method Extension1|method(final self::Class* #this) → core::int*
+  return #this.{self::Class::field1};
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+  return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+  return #this.{self::Class::field2};
+static method Extension2|set#field(final self::Class* #this, core::int* value) → core::int* {
+  final core::int* #t2 = value;
+  #this.{self::Class::field2} = value;
+  return #t2;
+}
+static method Extension2|method(final self::Class* #this) → core::int*
+  return #this.{self::Class::field2};
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+  return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+  self::Class* c = new self::Class::•();
+  self::expect(42, self::Extension1|get#field(c));
+  self::expect(87, self::Extension2|get#field(c));
+  self::expect(42, self::Extension1|method(c));
+  self::expect(87, self::Extension2|method(c));
+  () →* core::int* tearOff1 = self::Extension1|get#method(c);
+  () →* core::int* tearOff2 = self::Extension2|get#method(c);
+  self::expect(42, tearOff1.call());
+  self::expect(87, tearOff2.call());
+  self::expect(52, self::Extension1|genericMethod<core::int*>(c, 10));
+  self::expect(97, self::Extension2|genericMethod<core::int*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::num*>(c, 10));
+  self::expect(97, self::Extension2|genericMethod<core::num*>(c, 10));
+  <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c);
+  <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff2 = self::Extension2|get#genericMethod(c);
+  self::expect(52, genericTearOff1.call<core::int*>(10));
+  self::expect(97, genericTearOff2.call<core::int*>(10));
+  self::expect(52, genericTearOff1.call<core::num*>(10));
+  self::expect(97, genericTearOff2.call<core::num*>(10));
+  self::expect(23, self::Extension1|set#field(c, 23));
+  self::expect(67, self::Extension2|set#field(c, 67));
+  self::expect(23, self::Extension1|get#field(c));
+  self::expect(67, self::Extension2|get#field(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart
new file mode 100644
index 0000000..d2a63b9
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+class B extends A {}
+class C extends B {}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+  T get property => null;
+
+  T method(T t) => null;
+
+  S genericMethod1<S>(S s) => null;
+}
+
+main() {
+  A aVariable;
+  C cVariable;
+
+  GenericClass<A> aClass;
+  GenericClass<B> bClass;
+  GenericClass<C> cClass;
+
+  cVariable = GenericExtension(aClass).property;
+  cVariable = GenericExtension<A>(aClass).property;
+  cVariable = GenericExtension<B>(aClass).property;
+  cVariable = GenericExtension<C>(aClass).property;
+
+  cVariable = GenericExtension(bClass).property;
+  cVariable = GenericExtension<A>(bClass).property;
+  cVariable = GenericExtension<B>(bClass).property;
+  cVariable = GenericExtension<C>(bClass).property;
+
+  aVariable = GenericExtension(cClass).property;
+  aVariable = GenericExtension<A>(cClass).property;
+  aVariable = GenericExtension<B>(cClass).property;
+  aVariable = GenericExtension<C>(cClass).property;
+
+  cVariable = GenericExtension(aClass).method(aVariable);
+  cVariable = GenericExtension<A>(aClass).method(aVariable);
+  cVariable = GenericExtension<B>(aClass).method(aVariable);
+  cVariable = GenericExtension<C>(aClass).method(aVariable);
+
+  cVariable = GenericExtension(bClass).method(aVariable);
+  cVariable = GenericExtension<A>(bClass).method(aVariable);
+  cVariable = GenericExtension<B>(bClass).method(aVariable);
+  cVariable = GenericExtension<C>(bClass).method(aVariable);
+
+  aVariable = GenericExtension(cClass).method(aVariable);
+  aVariable = GenericExtension<A>(cClass).method(aVariable);
+  aVariable = GenericExtension<B>(cClass).method(aVariable);
+  aVariable = GenericExtension<C>(cClass).method(aVariable);
+
+  cVariable = GenericExtension(aClass).genericMethod1(aVariable);
+  cVariable = GenericExtension(aClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension(aClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension(aClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<A>(aClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<A>(aClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<A>(aClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<A>(aClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<B>(aClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<B>(aClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<B>(aClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<B>(aClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<C>(aClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<C>(aClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<C>(aClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<C>(aClass).genericMethod1<C>(aVariable);
+
+  cVariable = GenericExtension(bClass).genericMethod1(aVariable);
+  cVariable = GenericExtension(bClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension(bClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension(bClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<A>(bClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<A>(bClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<A>(bClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<A>(bClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<B>(bClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<B>(bClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<B>(bClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<B>(bClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<C>(bClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<C>(bClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<C>(bClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<C>(bClass).genericMethod1<C>(aVariable);
+
+  cVariable = GenericExtension(cClass).genericMethod1(aVariable);
+  cVariable = GenericExtension(cClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension(cClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension(cClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<A>(cClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<A>(cClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<A>(cClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<A>(cClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<B>(cClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<B>(cClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<B>(cClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<B>(cClass).genericMethod1<C>(aVariable);
+  cVariable = GenericExtension<C>(cClass).genericMethod1(aVariable);
+  cVariable = GenericExtension<C>(cClass).genericMethod1<A>(aVariable);
+  cVariable = GenericExtension<C>(cClass).genericMethod1<B>(aVariable);
+  cVariable = GenericExtension<C>(cClass).genericMethod1<C>(aVariable);
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect
new file mode 100644
index 0000000..b09bea2
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  ;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  ;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect
new file mode 100644
index 0000000..b3a12f5
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect
@@ -0,0 +1,120 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+  self::A* aVariable;
+  self::C* cVariable;
+  self::GenericClass<self::A*>* aClass;
+  self::GenericClass<self::B*>* bClass;
+  self::GenericClass<self::C*>* cClass;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*);
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::A*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*);
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::A*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::B*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  aVariable = self::GenericExtension|method<self::A*>(cClass, aVariable);
+  aVariable = self::GenericExtension|method<self::B*>(cClass, aVariable as{TypeError} self::B*);
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..b3a12f5
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect
@@ -0,0 +1,120 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+  self::A* aVariable;
+  self::C* cVariable;
+  self::GenericClass<self::A*>* aClass;
+  self::GenericClass<self::B*>* bClass;
+  self::GenericClass<self::C*>* cClass;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*);
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::A*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*);
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::A*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::B*>(cClass);
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  aVariable = self::GenericExtension|method<self::A*>(cClass, aVariable);
+  aVariable = self::GenericExtension|method<self::B*>(cClass, aVariable as{TypeError} self::B*);
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect
new file mode 100644
index 0000000..48040a1
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect
@@ -0,0 +1,216 @@
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:27:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:28:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:29:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:30:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:32:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:33:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:34:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:35:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:37:13: Context: Write to aVariable@453
+  aVariable = GenericExtension(cClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:38:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<A>(cClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:39:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<B>(cClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:40:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<C>(cClass).property;
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:42:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:43:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:44:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:45:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:47:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:48:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:49:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:50:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:52:13: Context: Write to aVariable@453
+  aVariable = GenericExtension(cClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:53:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<A>(cClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:54:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<B>(cClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:55:13: Context: Write to aVariable@453
+  aVariable = GenericExtension<C>(cClass).method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:57:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:58:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:59:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:60:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(aClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:61:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:62:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:63:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:64:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(aClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:65:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:66:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:67:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:68:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(aClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:69:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:70:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:71:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:72:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(aClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:74:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:75:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:76:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:77:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(bClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:78:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:79:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:80:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:81:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(bClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:82:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:83:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:84:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:85:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(bClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:86:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:87:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:88:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:89:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(bClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:91:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(cClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:92:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(cClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:93:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(cClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:94:13: Context: Write to cVariable@468
+  cVariable = GenericExtension(cClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:95:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(cClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:96:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(cClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:97:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(cClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:98:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<A>(cClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:99:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(cClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:100:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(cClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:101:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(cClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:102:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<B>(cClass).genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:103:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(cClass).genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:104:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(cClass).genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:105:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(cClass).genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:106:13: Context: Write to cVariable@468
+  cVariable = GenericExtension<C>(cClass).genericMethod1<C>(aVariable);
+            ^
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart
new file mode 100644
index 0000000..d8a4598
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class<T extends num> {
+  T field1;
+  T field2;
+
+  Class(this.field1, this.field2);
+}
+
+extension Extension1<T extends num> on Class<T> {
+  static String latestType;
+  T get field {
+    latestType = '$T';
+    return field1;
+  }
+  void set field(T value) {
+    latestType = '$T';
+    field1 = value;
+  }
+  T method() {
+    latestType = '$T';
+    return field1;
+  }
+  T genericMethod<S extends num>(S t) {
+    latestType = '$T:$S';
+    return field1 + t;
+  }
+}
+
+extension Extension2<T extends num> on Class<T> {
+  T get field => field2;
+  void set field(T value) {
+    field2 = value;
+  }
+  T method() => field2;
+  T genericMethod<S extends num>(S t) => field2 + t;
+}
+
+main() {
+  Class<int> c = new Class<int>(42, 87);
+  expect(42, Extension1<num>(c).field);
+  expect('num', Extension1.latestType);
+  expect(42, Extension1<int>(c).field);
+  expect('int', Extension1.latestType);
+  expect(87, Extension2<num>(c).field);
+
+  expect(42, Extension1<num>(c).method());
+  expect('num', Extension1.latestType);
+  expect(42, Extension1<int>(c).method());
+  expect('int', Extension1.latestType);
+  expect(87, Extension2<num>(c).method());
+  var tearOffNumber1 = Extension1<num>(c).method;
+  var tearOffInteger1 = Extension1<int>(c).method;
+  var tearOff2 = Extension2<num>(c).method;
+  expect(42, tearOffNumber1());
+  expect('num', Extension1.latestType);
+  expect(42, tearOffInteger1());
+  expect('int', Extension1.latestType);
+  expect(87, tearOff2());
+  expect(52, Extension1<num>(c).genericMethod(10));
+  expect('num:int', Extension1.latestType);
+  expect(52, Extension1<int>(c).genericMethod(10));
+  expect('int:int', Extension1.latestType);
+  expect(97, Extension2<num>(c).genericMethod(10));
+  expect(52, Extension1<num>(c).genericMethod<num>(10));
+  expect('num:num', Extension1.latestType);
+  expect(52, Extension1<int>(c).genericMethod<num>(10));
+  expect('int:num', Extension1.latestType);
+  expect(97, Extension2<num>(c).genericMethod<num>(10));
+  expect(52, Extension1(c).genericMethod(10));
+  expect('int:int', Extension1.latestType);
+  expect(52, Extension1(c).genericMethod<num>(10));
+  expect('int:num', Extension1.latestType);
+  expect(52, Extension1(c).genericMethod<int>(10));
+  expect('int:int', Extension1.latestType);
+  var genericTearOffNumber1 = Extension1<num>(c).genericMethod;
+  var genericTearOffInteger1 = Extension1<int>(c).genericMethod;
+  var genericTearOff2 = Extension2<num>(c).genericMethod;
+  expect(52, genericTearOffNumber1(10));
+  expect('num:int', Extension1.latestType);
+  expect(52, genericTearOffInteger1(10));
+  expect('int:int', Extension1.latestType);
+  expect(97, genericTearOff2(10));
+  expect(52, genericTearOffNumber1<num>(10));
+  expect('num:num', Extension1.latestType);
+  expect(52, genericTearOffInteger1<num>(10));
+  expect('int:num', Extension1.latestType);
+  expect(97, genericTearOff2<num>(10));
+  expect(23, Extension1<num>(c).field = 23);
+  expect('num', Extension1.latestType);
+  expect(23, Extension1<int>(c).field = 23);
+  expect('int', Extension1.latestType);
+  expect(67, Extension2<num>(c).field = 67);
+  expect(23, Extension1<num>(c).field);
+  expect(67, Extension2<num>(c).field);
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect
new file mode 100644
index 0000000..731ecb8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect
@@ -0,0 +1,56 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+  generic-covariant-impl field self::Class::T* field1;
+  generic-covariant-impl field self::Class::T* field2;
+  constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+    ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+  static field latestType = self::Extension1|latestType;
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T*
+  ;
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → void
+  ;
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T*
+  ;
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+  return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T*
+  ;
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+  ;
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → void
+  ;
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+  ;
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+  return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+  ;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect
new file mode 100644
index 0000000..e203cfb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect
@@ -0,0 +1,128 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+  generic-covariant-impl field self::Class::T* field1;
+  generic-covariant-impl field self::Class::T* field2;
+  constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+    : self::Class::field1 = field1, self::Class::field2 = field2, super core::Object::•()
+    ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+  static field latestType = self::Extension1|latestType;
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T* {
+  self::Extension1|latestType = "${self::Extension1|get#field::T*}";
+  return #this.{self::Class::field1};
+}
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → self::Extension1|set#field::T* {
+  final self::Extension1|set#field::T* #t1 = value;
+  self::Extension1|latestType = "${self::Extension1|set#field::T*}";
+  #this.{self::Class::field1} = value;
+  return #t1;
+}
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T* {
+  self::Extension1|latestType = "${self::Extension1|method::T*}";
+  return #this.{self::Class::field1};
+}
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+  return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T* {
+  self::Extension1|latestType = "${self::Extension1|genericMethod::T*}:${self::Extension1|genericMethod::S*}";
+  return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} self::Extension1|genericMethod::T*;
+}
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+  return #this.{self::Class::field2};
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → self::Extension2|set#field::T* {
+  final self::Extension2|set#field::T* #t2 = value;
+  #this.{self::Class::field2} = value;
+  return #t2;
+}
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+  return #this.{self::Class::field2};
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+  return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+  return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} self::Extension2|genericMethod::T*;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic {
+  self::Class<core::int*>* c = new self::Class::•<core::int*>(42, 87);
+  self::expect(42, self::Extension1|get#field<core::num*>(c));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, self::Extension1|get#field<core::int*>(c));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, self::Extension2|get#field<core::num*>(c));
+  self::expect(42, self::Extension1|method<core::num*>(c));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, self::Extension1|method<core::int*>(c));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, self::Extension2|method<core::num*>(c));
+  () →* core::num* tearOffNumber1 = self::Extension1|get#method<core::num*>(c);
+  () →* core::int* tearOffInteger1 = self::Extension1|get#method<core::int*>(c);
+  () →* core::num* tearOff2 = self::Extension2|get#method<core::num*>(c);
+  self::expect(42, tearOffNumber1.call());
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, tearOffInteger1.call());
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, tearOff2.call());
+  self::expect(52, self::Extension1|genericMethod<core::num*, core::int*>(c, 10));
+  self::expect("num:int", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(97, self::Extension2|genericMethod<core::num*, core::int*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::num*, core::num*>(c, 10));
+  self::expect("num:num", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(97, self::Extension2|genericMethod<core::num*, core::num*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  <S extends core::num* = dynamic>(S*) →* core::num* genericTearOffNumber1 = self::Extension1|get#genericMethod<core::num*>(c);
+  <S extends core::num* = dynamic>(S*) →* core::int* genericTearOffInteger1 = self::Extension1|get#genericMethod<core::int*>(c);
+  <S extends core::num* = dynamic>(S*) →* core::num* genericTearOff2 = self::Extension2|get#genericMethod<core::num*>(c);
+  self::expect(52, genericTearOffNumber1.call<core::int*>(10));
+  self::expect("num:int", self::Extension1|latestType);
+  self::expect(52, genericTearOffInteger1.call<core::int*>(10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(97, genericTearOff2.call<core::int*>(10));
+  self::expect(52, genericTearOffNumber1.call<core::num*>(10));
+  self::expect("num:num", self::Extension1|latestType);
+  self::expect(52, genericTearOffInteger1.call<core::num*>(10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(97, genericTearOff2.call<core::num*>(10));
+  self::expect(23, self::Extension1|set#field<core::num*>(c, 23));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(23, self::Extension1|set#field<core::int*>(c, 23));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(67, self::Extension2|set#field<core::num*>(c, 67));
+  self::expect(23, self::Extension1|get#field<core::num*>(c));
+  self::expect(67, self::Extension2|get#field<core::num*>(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..e203cfb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect
@@ -0,0 +1,128 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+  generic-covariant-impl field self::Class::T* field1;
+  generic-covariant-impl field self::Class::T* field2;
+  constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+    : self::Class::field1 = field1, self::Class::field2 = field2, super core::Object::•()
+    ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+  static field latestType = self::Extension1|latestType;
+  get field = self::Extension1|get#field;
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+  get field = self::Extension2|get#field;
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T* {
+  self::Extension1|latestType = "${self::Extension1|get#field::T*}";
+  return #this.{self::Class::field1};
+}
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → self::Extension1|set#field::T* {
+  final self::Extension1|set#field::T* #t1 = value;
+  self::Extension1|latestType = "${self::Extension1|set#field::T*}";
+  #this.{self::Class::field1} = value;
+  return #t1;
+}
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T* {
+  self::Extension1|latestType = "${self::Extension1|method::T*}";
+  return #this.{self::Class::field1};
+}
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+  return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T* {
+  self::Extension1|latestType = "${self::Extension1|genericMethod::T*}:${self::Extension1|genericMethod::S*}";
+  return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} self::Extension1|genericMethod::T*;
+}
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+  return #this.{self::Class::field2};
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → self::Extension2|set#field::T* {
+  final self::Extension2|set#field::T* #t2 = value;
+  #this.{self::Class::field2} = value;
+  return #t2;
+}
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+  return #this.{self::Class::field2};
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+  return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+  return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} self::Extension2|genericMethod::T*;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+  return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic {
+  self::Class<core::int*>* c = new self::Class::•<core::int*>(42, 87);
+  self::expect(42, self::Extension1|get#field<core::num*>(c));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, self::Extension1|get#field<core::int*>(c));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, self::Extension2|get#field<core::num*>(c));
+  self::expect(42, self::Extension1|method<core::num*>(c));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, self::Extension1|method<core::int*>(c));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, self::Extension2|method<core::num*>(c));
+  () →* core::num* tearOffNumber1 = self::Extension1|get#method<core::num*>(c);
+  () →* core::int* tearOffInteger1 = self::Extension1|get#method<core::int*>(c);
+  () →* core::num* tearOff2 = self::Extension2|get#method<core::num*>(c);
+  self::expect(42, tearOffNumber1.call());
+  self::expect("num", self::Extension1|latestType);
+  self::expect(42, tearOffInteger1.call());
+  self::expect("int", self::Extension1|latestType);
+  self::expect(87, tearOff2.call());
+  self::expect(52, self::Extension1|genericMethod<core::num*, core::int*>(c, 10));
+  self::expect("num:int", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(97, self::Extension2|genericMethod<core::num*, core::int*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::num*, core::num*>(c, 10));
+  self::expect("num:num", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(97, self::Extension2|genericMethod<core::num*, core::num*>(c, 10));
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+  self::expect("int:int", self::Extension1|latestType);
+  <S extends core::num* = dynamic>(S*) →* core::num* genericTearOffNumber1 = self::Extension1|get#genericMethod<core::num*>(c);
+  <S extends core::num* = dynamic>(S*) →* core::int* genericTearOffInteger1 = self::Extension1|get#genericMethod<core::int*>(c);
+  <S extends core::num* = dynamic>(S*) →* core::num* genericTearOff2 = self::Extension2|get#genericMethod<core::num*>(c);
+  self::expect(52, genericTearOffNumber1.call<core::int*>(10));
+  self::expect("num:int", self::Extension1|latestType);
+  self::expect(52, genericTearOffInteger1.call<core::int*>(10));
+  self::expect("int:int", self::Extension1|latestType);
+  self::expect(97, genericTearOff2.call<core::int*>(10));
+  self::expect(52, genericTearOffNumber1.call<core::num*>(10));
+  self::expect("num:num", self::Extension1|latestType);
+  self::expect(52, genericTearOffInteger1.call<core::num*>(10));
+  self::expect("int:num", self::Extension1|latestType);
+  self::expect(97, genericTearOff2.call<core::num*>(10));
+  self::expect(23, self::Extension1|set#field<core::num*>(c, 23));
+  self::expect("num", self::Extension1|latestType);
+  self::expect(23, self::Extension1|set#field<core::int*>(c, 23));
+  self::expect("int", self::Extension1|latestType);
+  self::expect(67, self::Extension2|set#field<core::num*>(c, 67));
+  self::expect(23, self::Extension1|get#field<core::num*>(c));
+  self::expect(67, self::Extension2|get#field<core::num*>(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect
new file mode 100644
index 0000000..b4cc663
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect
@@ -0,0 +1,12 @@
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:15:16: Context: Write to latestType@375
+    latestType = '$T';
+               ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:19:16: Context: Write to latestType@375
+    latestType = '$T';
+               ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:23:16: Context: Write to latestType@375
+    latestType = '$T';
+               ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:27:16: Context: Write to latestType@375
+    latestType = '$T:$S';
+               ^
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
index 0819186..ccf3c26 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   ;
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   ;
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void
   ;
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void {
   #this.{self::A1::field} = o;
 }
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void {
   #this.{self::A1::field} = o;
 }
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
index ebd3f24..b1e71de 100644
--- a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
@@ -1,13 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
-//  - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-//   var result = c.one + c.two;
-//                          ^^^
-//
 import self as self;
 import "dart:core" as core;
 import "package:expect/expect.dart" as exp;
@@ -28,10 +19,6 @@
   return 2;
 static method main() → dynamic {
   self::C* c = new self::C::•();
-  core::num* result = c.{self::C::one}.{core::num::+}(invalid-expression "pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
- - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-  var result = c.one + c.two;
-                         ^^^" as{TypeError} core::num*);
+  core::int* result = c.{self::C::one}.{core::num::+}(self::E|get#two(c));
   exp::Expect::equals(result, 3);
 }
diff --git a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
index ebd3f24..b1e71de 100644
--- a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
@@ -1,13 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
-//  - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-//   var result = c.one + c.two;
-//                          ^^^
-//
 import self as self;
 import "dart:core" as core;
 import "package:expect/expect.dart" as exp;
@@ -28,10 +19,6 @@
   return 2;
 static method main() → dynamic {
   self::C* c = new self::C::•();
-  core::num* result = c.{self::C::one}.{core::num::+}(invalid-expression "pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
- - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-  var result = c.one + c.two;
-                         ^^^" as{TypeError} core::num*);
+  core::int* result = c.{self::C::one}.{core::num::+}(self::E|get#two(c));
   exp::Expect::equals(result, 3);
 }
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart
new file mode 100644
index 0000000..fe69fc8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+class B extends A {}
+class C extends B {}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+  T get property => null;
+
+  T method(T t) => null;
+
+  S genericMethod1<S>(S s) => null;
+}
+
+main() {
+  A aVariable;
+  C cVariable;
+
+  GenericClass<A> aClass;
+  GenericClass<B> bClass;
+  GenericClass<C> cClass;
+
+  cVariable = aClass.property;
+  cVariable = bClass.property;
+  aVariable = cClass.property;
+
+  cVariable = aClass.method(aVariable);
+  cVariable = bClass.method(aVariable);
+  aVariable = cClass.method(aVariable);
+
+  cVariable = aClass.genericMethod1(aVariable);
+  cVariable = aClass.genericMethod1<A>(aVariable);
+  cVariable = aClass.genericMethod1<B>(aVariable);
+  cVariable = aClass.genericMethod1<C>(aVariable);
+
+  cVariable = bClass.genericMethod1(aVariable);
+  cVariable = bClass.genericMethod1<A>(aVariable);
+  cVariable = bClass.genericMethod1<B>(aVariable);
+  cVariable = bClass.genericMethod1<C>(aVariable);
+
+  cVariable = cClass.genericMethod1(aVariable);
+  cVariable = cClass.genericMethod1<A>(aVariable);
+  cVariable = cClass.genericMethod1<B>(aVariable);
+  cVariable = cClass.genericMethod1<C>(aVariable);
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect
new file mode 100644
index 0000000..b09bea2
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  ;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  ;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect
new file mode 100644
index 0000000..1bf8085
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+  self::A* aVariable;
+  self::C* cVariable;
+  self::GenericClass<self::A*>* aClass;
+  self::GenericClass<self::B*>* bClass;
+  self::GenericClass<self::C*>* cClass;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..1bf8085
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  get property = self::GenericExtension|get#property;
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+  method genericMethod1 = self::GenericExtension|genericMethod1;
+  tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+  return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+  return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+  return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+  return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+  return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+  self::A* aVariable;
+  self::C* cVariable;
+  self::GenericClass<self::A*>* aClass;
+  self::GenericClass<self::B*>* bClass;
+  self::GenericClass<self::C*>* cClass;
+  cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+  aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+  cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+  cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect
new file mode 100644
index 0000000..c086585
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect
@@ -0,0 +1,54 @@
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:27:13: Context: Write to cVariable@468
+  cVariable = aClass.property;
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:28:13: Context: Write to cVariable@468
+  cVariable = bClass.property;
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:29:13: Context: Write to aVariable@453
+  aVariable = cClass.property;
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:31:13: Context: Write to cVariable@468
+  cVariable = aClass.method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:32:13: Context: Write to cVariable@468
+  cVariable = bClass.method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:33:13: Context: Write to aVariable@453
+  aVariable = cClass.method(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:35:13: Context: Write to cVariable@468
+  cVariable = aClass.genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:36:13: Context: Write to cVariable@468
+  cVariable = aClass.genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:37:13: Context: Write to cVariable@468
+  cVariable = aClass.genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:38:13: Context: Write to cVariable@468
+  cVariable = aClass.genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:40:13: Context: Write to cVariable@468
+  cVariable = bClass.genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:41:13: Context: Write to cVariable@468
+  cVariable = bClass.genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:42:13: Context: Write to cVariable@468
+  cVariable = bClass.genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:43:13: Context: Write to cVariable@468
+  cVariable = bClass.genericMethod1<C>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:45:13: Context: Write to cVariable@468
+  cVariable = cClass.genericMethod1(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:46:13: Context: Write to cVariable@468
+  cVariable = cClass.genericMethod1<A>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:47:13: Context: Write to cVariable@468
+  cVariable = cClass.genericMethod1<B>(aVariable);
+            ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:48:13: Context: Write to cVariable@468
+  cVariable = cClass.genericMethod1<C>(aVariable);
+            ^
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
index 0819186..ccf3c26 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   ;
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   ;
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void
   ;
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void {
   #this.{self::A1::field} = o;
 }
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
@@ -11,14 +11,23 @@
 }
 extension A2 on self::A1* {
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 static method A2|method2(final self::A1* #this) → void
   return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+  return () → void => self::A2|method2(#this);
 static method A2|method3(final self::A1* #this) → core::Object*
   return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+  return () → core::Object* => self::A2|method3(#this);
 static method A2|method4(final self::A1* #this, core::Object* o) → void {
   #this.{self::A1::field} = o;
 }
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+  return (core::Object* o) → void => self::A2|method4(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/index.dart b/pkg/front_end/testcases/extensions/index.dart
new file mode 100644
index 0000000..f34eac8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class MapLike<K, V> {
+  final Map<K, V> _map = {};
+
+  V get(Object key) => _map[key];
+  V put(K key, V value) => _map[key] = value;
+}
+
+extension Extension<K, V> on MapLike<K, V> {
+  V operator [](Object key) => get(key);
+  void operator []=(K key, V value) => put(key, value);
+}
+
+main() {
+  MapLike<int, String> map1 = new MapLike();
+  expect(null, map1[0]);
+  map1.put(0, '0');
+  expect('0', map1[0]);
+  expect(null, map1[1]);
+  expect('1', map1[1] = '1');
+  expect('1', map1[1]);
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/index.dart.outline.expect b/pkg/front_end/testcases/extensions/index.dart.outline.expect
new file mode 100644
index 0000000..c9b2e9d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.outline.expect
@@ -0,0 +1,25 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+  final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map;
+  synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+    ;
+  method get(core::Object* key) → self::MapLike::V*
+    ;
+  method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+    ;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+  ;
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.expect b/pkg/front_end/testcases/extensions/index.dart.strong.expect
new file mode 100644
index 0000000..70bdb38
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+  final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map = <self::MapLike::K*, self::MapLike::V*>{};
+  synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+    : super core::Object::•()
+    ;
+  method get(core::Object* key) → self::MapLike::V*
+    return this.{self::MapLike::_map}.{core::Map::[]}(key);
+  method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+    return let final core::Map<self::MapLike::K*, self::MapLike::V*>* #t1 = this.{self::MapLike::_map} in let final self::MapLike::K* #t2 = key in let final self::MapLike::V* #t3 = value in let final void #t4 = #t1.{core::Map::[]=}(#t2, #t3) in #t3;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+  return #this.{self::MapLike::get}(key);
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+  return #this.{self::MapLike::put}(key, value);
+static method main() → dynamic {
+  self::MapLike<core::int*, core::String*>* map1 = new self::MapLike::•<core::int*, core::String*>();
+  self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 0));
+  map1.{self::MapLike::put}(0, "0");
+  self::expect("0", self::Extension|[]<core::int*, core::String*>(map1, 0));
+  self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 1));
+  self::expect("1", let final self::MapLike<core::int*, core::String*>* #t5 = map1 in let final core::int* #t6 = 1 in let final core::String* #t7 = "1" in let final void #t8 = self::Extension|[]=<core::int*, core::String*>(#t5, #t6, #t7) in #t7);
+  self::expect("1", self::Extension|[]<core::int*, core::String*>(map1, 1));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
new file mode 100644
index 0000000..70bdb38
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+  final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map = <self::MapLike::K*, self::MapLike::V*>{};
+  synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+    : super core::Object::•()
+    ;
+  method get(core::Object* key) → self::MapLike::V*
+    return this.{self::MapLike::_map}.{core::Map::[]}(key);
+  method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+    return let final core::Map<self::MapLike::K*, self::MapLike::V*>* #t1 = this.{self::MapLike::_map} in let final self::MapLike::K* #t2 = key in let final self::MapLike::V* #t3 = value in let final void #t4 = #t1.{core::Map::[]=}(#t2, #t3) in #t3;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+  return #this.{self::MapLike::get}(key);
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+  return #this.{self::MapLike::put}(key, value);
+static method main() → dynamic {
+  self::MapLike<core::int*, core::String*>* map1 = new self::MapLike::•<core::int*, core::String*>();
+  self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 0));
+  map1.{self::MapLike::put}(0, "0");
+  self::expect("0", self::Extension|[]<core::int*, core::String*>(map1, 0));
+  self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 1));
+  self::expect("1", let final self::MapLike<core::int*, core::String*>* #t5 = map1 in let final core::int* #t6 = 1 in let final core::String* #t7 = "1" in let final void #t8 = self::Extension|[]=<core::int*, core::String*>(#t5, #t6, #t7) in #t7);
+  self::expect("1", self::Extension|[]<core::int*, core::String*>(map1, 1));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart b/pkg/front_end/testcases/extensions/instance_access.dart
new file mode 100644
index 0000000..249f712
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+  int field;
+
+  Class1(this.field);
+
+  String toString() => 'Class1($field)';
+}
+
+class Class2 {
+  int field;
+
+  Class2(this.field);
+
+  String toString() => 'Class2($field)';
+}
+
+extension Extension1 on Class1 {
+  int method() {
+    print('Extension1.method on $this');
+    return field;
+  }
+  int genericMethod<T extends num>(T t) {
+    print('Extension1.genericMethod<$T>($t) on $this');
+    return field + t;
+  }
+  int get property {
+    print('Extension1.property get on $this');
+    return field;
+  }
+  set property(int value) {
+    field = value;
+    print('Extension1.property set($value) on $this');
+    value++;
+  }
+}
+
+
+extension Extension2 on Class2 {
+  int method() {
+    print('Extension2.method on $this');
+    return field + 3;
+  }
+  int genericMethod<T extends num>(T t) {
+    print('Extension2.genericMethod<$T>($t) on $this');
+    return field + t + 4;
+  }
+  int get property {
+    print('Extension2.property get on $this');
+    return field + 5;
+  }
+  set property(int value) {
+    print('Extension2.property set($value) on $this');
+    value++;
+    field = value;
+  }
+}
+
+main() {
+  testExtension1();
+  testExtension2();
+}
+
+testExtension1() {
+  Class1 c0 = new Class1(0);
+  Class1 c1 = new Class1(1);
+  expect(0, c0.method());
+  expect(1, c1.method());
+  expect(42, c0.genericMethod(42));
+  expect(43, c0.genericMethod<num>(43));
+  expect(88, c1.genericMethod(87));
+  expect(89, c1.genericMethod<num>(88));
+  expect(0, c0.property);
+  expect(42, c0.property = 42);
+  expect(1, c1.property);
+  expect(87, c0.property = 87);
+  expect(27, c0.property = c1.property = 27);
+  expect(37, c1.property = c0.property = 37);
+  expect(77, c1.property = c0.property = c1.property = 77);
+  expect(67, c0.property = c1.property = c0.property = 67);
+}
+
+testExtension2() {
+  Class2 c0 = new Class2(0);
+  Class2 c1 = new Class2(1);
+  expect(3, c0.method());
+  expect(4, c1.method());
+  expect(46, c0.genericMethod(42));
+  expect(47, c0.genericMethod<num>(43));
+  expect(92, c1.genericMethod(87));
+  expect(93, c1.genericMethod<num>(88));
+  expect(5, c0.property);
+  expect(42, c0.property = 42);
+  expect(48, c0.property);
+  expect(6, c1.property);
+  expect(43, c1.property = 43);
+  expect(49, c1.property);
+  expect(49, c0.property = c1.property);
+  expect(55, c1.property = c0.property);
+  expect(61, c1.property = c0.property = c1.property);
+  expect(67, c0.property = c1.property = c0.property);
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect
new file mode 100644
index 0000000..c0d9552
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    ;
+  method toString() → core::String*
+    ;
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    ;
+  method toString() → core::String*
+    ;
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  get property = self::Extension1|get#property;
+  set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  get property = self::Extension2|get#property;
+  set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int*
+  ;
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int*
+  ;
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int*
+  ;
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → void
+  ;
+static method Extension2|method(final self::Class2* #this) → core::int*
+  ;
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int*
+  ;
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int*
+  ;
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → void
+  ;
+static method main() → dynamic
+  ;
+static method testExtension1() → dynamic
+  ;
+static method testExtension2() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect
new file mode 100644
index 0000000..1417dd4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect
@@ -0,0 +1,129 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  get property = self::Extension1|get#property;
+  set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  get property = self::Extension2|get#property;
+  set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+  core::print("Extension1.method on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+  core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int* {
+  core::print("Extension1.property get on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
+  #this.{self::Class1::field} = value;
+  core::print("Extension1.property set(${value}) on ${#this}");
+  value = value.{core::num::+}(1);
+  return #t1;
+}
+static method Extension2|method(final self::Class2* #this) → core::int* {
+  core::print("Extension2.method on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(3);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+  core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(4) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int* {
+  core::print("Extension2.property get on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(5);
+}
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → core::int* {
+  final core::int* #t2 = value;
+  core::print("Extension2.property set(${value}) on ${#this}");
+  value = value.{core::num::+}(1);
+  #this.{self::Class2::field} = value;
+  return #t2;
+}
+static method main() → dynamic {
+  self::testExtension1();
+  self::testExtension2();
+}
+static method testExtension1() → dynamic {
+  self::Class1* c0 = new self::Class1::•(0);
+  self::Class1* c1 = new self::Class1::•(1);
+  self::expect(0, self::Extension1|method(c0));
+  self::expect(1, self::Extension1|method(c1));
+  self::expect(42, self::Extension1|genericMethod<core::int*>(c0, 42));
+  self::expect(43, self::Extension1|genericMethod<core::num*>(c0, 43));
+  self::expect(88, self::Extension1|genericMethod<core::int*>(c1, 87));
+  self::expect(89, self::Extension1|genericMethod<core::num*>(c1, 88));
+  self::expect(0, self::Extension1|get#property(c0));
+  self::expect(42, self::Extension1|set#property(c0, 42));
+  self::expect(1, self::Extension1|get#property(c1));
+  self::expect(87, self::Extension1|set#property(c0, 87));
+  self::expect(27, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 27)));
+  self::expect(37, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 37)));
+  self::expect(77, self::Extension1|set#property(c1, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 77))));
+  self::expect(67, self::Extension1|set#property(c0, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 67))));
+}
+static method testExtension2() → dynamic {
+  self::Class2* c0 = new self::Class2::•(0);
+  self::Class2* c1 = new self::Class2::•(1);
+  self::expect(3, self::Extension2|method(c0));
+  self::expect(4, self::Extension2|method(c1));
+  self::expect(46, self::Extension2|genericMethod<core::int*>(c0, 42));
+  self::expect(47, self::Extension2|genericMethod<core::num*>(c0, 43));
+  self::expect(92, self::Extension2|genericMethod<core::int*>(c1, 87));
+  self::expect(93, self::Extension2|genericMethod<core::num*>(c1, 88));
+  self::expect(5, self::Extension2|get#property(c0));
+  self::expect(42, self::Extension2|set#property(c0, 42));
+  self::expect(48, self::Extension2|get#property(c0));
+  self::expect(6, self::Extension2|get#property(c1));
+  self::expect(43, self::Extension2|set#property(c1, 43));
+  self::expect(49, self::Extension2|get#property(c1));
+  self::expect(49, self::Extension2|set#property(c0, self::Extension2|get#property(c1)));
+  self::expect(55, self::Extension2|set#property(c1, self::Extension2|get#property(c0)));
+  self::expect(61, self::Extension2|set#property(c1, self::Extension2|set#property(c0, self::Extension2|get#property(c1))));
+  self::expect(67, self::Extension2|set#property(c0, self::Extension2|set#property(c1, self::Extension2|get#property(c0))));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..1417dd4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect
@@ -0,0 +1,129 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+  get property = self::Extension1|get#property;
+  set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+  get property = self::Extension2|get#property;
+  set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+  core::print("Extension1.method on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+  core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int* {
+  core::print("Extension1.property get on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
+  #this.{self::Class1::field} = value;
+  core::print("Extension1.property set(${value}) on ${#this}");
+  value = value.{core::num::+}(1);
+  return #t1;
+}
+static method Extension2|method(final self::Class2* #this) → core::int* {
+  core::print("Extension2.method on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(3);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+  core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(4) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int* {
+  core::print("Extension2.property get on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(5);
+}
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → core::int* {
+  final core::int* #t2 = value;
+  core::print("Extension2.property set(${value}) on ${#this}");
+  value = value.{core::num::+}(1);
+  #this.{self::Class2::field} = value;
+  return #t2;
+}
+static method main() → dynamic {
+  self::testExtension1();
+  self::testExtension2();
+}
+static method testExtension1() → dynamic {
+  self::Class1* c0 = new self::Class1::•(0);
+  self::Class1* c1 = new self::Class1::•(1);
+  self::expect(0, self::Extension1|method(c0));
+  self::expect(1, self::Extension1|method(c1));
+  self::expect(42, self::Extension1|genericMethod<core::int*>(c0, 42));
+  self::expect(43, self::Extension1|genericMethod<core::num*>(c0, 43));
+  self::expect(88, self::Extension1|genericMethod<core::int*>(c1, 87));
+  self::expect(89, self::Extension1|genericMethod<core::num*>(c1, 88));
+  self::expect(0, self::Extension1|get#property(c0));
+  self::expect(42, self::Extension1|set#property(c0, 42));
+  self::expect(1, self::Extension1|get#property(c1));
+  self::expect(87, self::Extension1|set#property(c0, 87));
+  self::expect(27, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 27)));
+  self::expect(37, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 37)));
+  self::expect(77, self::Extension1|set#property(c1, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 77))));
+  self::expect(67, self::Extension1|set#property(c0, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 67))));
+}
+static method testExtension2() → dynamic {
+  self::Class2* c0 = new self::Class2::•(0);
+  self::Class2* c1 = new self::Class2::•(1);
+  self::expect(3, self::Extension2|method(c0));
+  self::expect(4, self::Extension2|method(c1));
+  self::expect(46, self::Extension2|genericMethod<core::int*>(c0, 42));
+  self::expect(47, self::Extension2|genericMethod<core::num*>(c0, 43));
+  self::expect(92, self::Extension2|genericMethod<core::int*>(c1, 87));
+  self::expect(93, self::Extension2|genericMethod<core::num*>(c1, 88));
+  self::expect(5, self::Extension2|get#property(c0));
+  self::expect(42, self::Extension2|set#property(c0, 42));
+  self::expect(48, self::Extension2|get#property(c0));
+  self::expect(6, self::Extension2|get#property(c1));
+  self::expect(43, self::Extension2|set#property(c1, 43));
+  self::expect(49, self::Extension2|get#property(c1));
+  self::expect(49, self::Extension2|set#property(c0, self::Extension2|get#property(c1)));
+  self::expect(55, self::Extension2|set#property(c1, self::Extension2|get#property(c0)));
+  self::expect(61, self::Extension2|set#property(c1, self::Extension2|set#property(c0, self::Extension2|get#property(c1))));
+  self::expect(67, self::Extension2|set#property(c0, self::Extension2|set#property(c1, self::Extension2|get#property(c0))));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect
new file mode 100644
index 0000000..052b274
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect
@@ -0,0 +1,6 @@
+pkg/front_end/testcases/extensions/instance_access.dart:37:10: Context: Write to value@755
+    value++;
+         ^^
+pkg/front_end/testcases/extensions/instance_access.dart:57:10: Context: Write to value@1217
+    value++;
+         ^^
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart b/pkg/front_end/testcases/extensions/instance_access_of_static.dart
new file mode 100644
index 0000000..a8b0b2d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+}
+
+extension Extension1 on Class1 {
+  static staticMethod() {
+    print('Extension1.staticMethod()');
+  }
+
+  static get staticProperty {
+    print('Extension1.staticProperty()');
+  }
+  static set staticProperty(int value) {
+    print('Extension1.staticProperty($value)');
+    value++;
+  }
+
+  static var staticField = 42;
+}
+
+main() {
+  Class1 c = new Class1();
+  c.staticMethod();
+  c.staticMethod;
+  c.staticProperty;
+  c.staticProperty = 42;
+  c.staticField;
+  c.staticField = 42;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect
new file mode 100644
index 0000000..731aa09
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    ;
+}
+extension Extension1 on self::Class1* {
+  static method staticMethod = self::Extension1|staticMethod;
+  static get staticProperty = get self::Extension1|staticProperty;
+  static field staticField = self::Extension1|staticField;
+  static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField;
+static method Extension1|staticMethod() → dynamic
+  ;
+static get Extension1|staticProperty() → dynamic
+  ;
+static set Extension1|staticProperty(core::int* value) → void
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect
new file mode 100644
index 0000000..75191b4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect
@@ -0,0 +1,98 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+//   c.staticMethod();
+//     ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+//   c.staticMethod;
+//     ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+//   c.staticProperty;
+//     ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+//   c.staticProperty = 42;
+//     ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+//   c.staticField;
+//     ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+//   c.staticField = 42;
+//     ^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    : super core::Object::•()
+    ;
+}
+extension Extension1 on self::Class1* {
+  static method staticMethod = self::Extension1|staticMethod;
+  static get staticProperty = get self::Extension1|staticProperty;
+  static field staticField = self::Extension1|staticField;
+  static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField = 42;
+static method Extension1|staticMethod() → dynamic {
+  core::print("Extension1.staticMethod()");
+}
+static get Extension1|staticProperty() → dynamic {
+  core::print("Extension1.staticProperty()");
+}
+static set Extension1|staticProperty(core::int* value) → void {
+  core::print("Extension1.staticProperty(${value})");
+  value = value.{core::num::+}(1);
+}
+static method main() → dynamic {
+  self::Class1* c = new self::Class1::•();
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+  c.staticMethod();
+    ^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+  c.staticMethod;
+    ^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+  c.staticProperty;
+    ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+  c.staticProperty = 42;
+    ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+  c.staticField;
+    ^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+  c.staticField = 42;
+    ^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect
new file mode 100644
index 0000000..75191b4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect
@@ -0,0 +1,98 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+//   c.staticMethod();
+//     ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+//   c.staticMethod;
+//     ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+//   c.staticProperty;
+//     ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+//   c.staticProperty = 42;
+//     ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+//   c.staticField;
+//     ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+//  - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+//   c.staticField = 42;
+//     ^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    : super core::Object::•()
+    ;
+}
+extension Extension1 on self::Class1* {
+  static method staticMethod = self::Extension1|staticMethod;
+  static get staticProperty = get self::Extension1|staticProperty;
+  static field staticField = self::Extension1|staticField;
+  static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField = 42;
+static method Extension1|staticMethod() → dynamic {
+  core::print("Extension1.staticMethod()");
+}
+static get Extension1|staticProperty() → dynamic {
+  core::print("Extension1.staticProperty()");
+}
+static set Extension1|staticProperty(core::int* value) → void {
+  core::print("Extension1.staticProperty(${value})");
+  value = value.{core::num::+}(1);
+}
+static method main() → dynamic {
+  self::Class1* c = new self::Class1::•();
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+  c.staticMethod();
+    ^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+  c.staticMethod;
+    ^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+  c.staticProperty;
+    ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+  c.staticProperty = 42;
+    ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+  c.staticField;
+    ^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+  c.staticField = 42;
+    ^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect
new file mode 100644
index 0000000..2967660
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/extensions/instance_access_of_static.dart:18:10: Context: Write to value@447
+    value++;
+         ^^
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
index c2ae0c9..36c0330 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
@@ -12,25 +12,43 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1*
   ;
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1*
   ;
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
 static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this, [self::A2|method3::T* o]) → self::A1*
   ;
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+  return <T extends core::Object* = dynamic>([T* o = null]) → self::A1* => self::A2|method3<T*>(#this, o);
 static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this, {self::A2|method4::T* o}) → self::A1*
   ;
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>*
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+  return <T extends core::Object* = dynamic>({T* o = null}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>*
   ;
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>*
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>*
   ;
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
index 598e9a6..dfed3fb 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
@@ -14,36 +14,54 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1* {
   return #this;
 }
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
   core::print(o);
   return #this;
 }
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
 static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this = #C1, [self::A2|method3::T* o = #C1]) → self::A1* {
   core::print(o);
   return #this;
 }
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+  return <T extends core::Object* = dynamic>([T* o = #C1]) → self::A1* => self::A2|method3<T*>(#this, o);
 static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this = #C1, {self::A2|method4::T* o = #C1}) → self::A1* {
   core::print(o);
   return #this;
 }
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+  return <T extends core::Object* = dynamic>({T* o = #C1}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
   return #this;
 }
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
   core::print(o);
   return #this;
 }
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
index 598e9a6..dfed3fb 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
@@ -14,36 +14,54 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
   method method3 = self::A2|method3;
+  tearoff method3 = self::A2|get#method3;
   method method4 = self::A2|method4;
+  tearoff method4 = self::A2|get#method4;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1* {
   return #this;
 }
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
   core::print(o);
   return #this;
 }
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
 static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this = #C1, [self::A2|method3::T* o = #C1]) → self::A1* {
   core::print(o);
   return #this;
 }
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+  return <T extends core::Object* = dynamic>([T* o = #C1]) → self::A1* => self::A2|method3<T*>(#this, o);
 static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this = #C1, {self::A2|method4::T* o = #C1}) → self::A1* {
   core::print(o);
   return #this;
 }
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+  return <T extends core::Object* = dynamic>({T* o = #C1}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
   return #this;
 }
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
   core::print(o);
   return #this;
 }
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart b/pkg/front_end/testcases/extensions/instance_tearoff.dart
new file mode 100644
index 0000000..9689df3
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+  int field;
+
+  Class1(this.field);
+
+  String toString() => 'Class1($field)';
+}
+
+class Class2 {
+  int field;
+
+  Class2(this.field);
+
+  String toString() => 'Class2($field)';
+}
+
+extension Extension1 on Class1 {
+  int method() {
+    print('Extension1.method on $this');
+    return field;
+  }
+  int genericMethod<T extends num>(T t) {
+    print('Extension1.genericMethod<$T>($t) on $this');
+    return field + t;
+  }
+}
+
+
+extension Extension2 on Class2 {
+  int method() {
+    print('Extension2.method on $this');
+    return field + 2;
+  }
+  int genericMethod<T extends num>(T t) {
+    print('Extension2.genericMethod<$T>($t) on $this');
+    return field + t + 3;
+  }
+}
+
+main() {
+  testExtension1();
+  testExtension2();
+}
+
+testExtension1() {
+  Class1 c0 = new Class1(0);
+  Class1 c1 = new Class1(1);
+  var tearOff0 = c0.method;
+  expect(0, tearOff0());
+  c0 = new Class1(-4);
+  expect(0, tearOff0());
+  var tearOff1 = c1.method;
+  expect(1, tearOff1());
+  c1 = new Class1(-7);
+  expect(1, tearOff1());
+  var genericTearOff0 = c0.genericMethod;
+  expect(38, genericTearOff0(42));
+  expect(38, genericTearOff0<num>(42));
+  var genericTearOff1 = c1.genericMethod;
+  expect(35, genericTearOff1(42));
+  expect(35, genericTearOff1<num>(42));
+}
+
+testExtension2() {
+  Class2 c0 = new Class2(0);
+  Class2 c1 = new Class2(1);
+  var tearOff0 = c0.method;
+  expect(2, tearOff0());
+  c0 = new Class2(-4);
+  expect(2, tearOff0());
+  var tearOff1 = c1.method;
+  expect(3, tearOff1());
+  c1 = new Class2(-7);
+  expect(3, tearOff1());
+  var genericTearOff0 = c0.genericMethod;
+  expect(41, genericTearOff0(42));
+  expect(41, genericTearOff0<num>(42));
+  var genericTearOff1 = c1.genericMethod;
+  expect(38, genericTearOff1(42));
+  expect(38, genericTearOff1<num>(42));
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect
new file mode 100644
index 0000000..d50804e
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect
@@ -0,0 +1,54 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    ;
+  method toString() → core::String*
+    ;
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    ;
+  method toString() → core::String*
+    ;
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int*
+  ;
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int*
+  ;
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int*
+  ;
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int*
+  ;
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic
+  ;
+static method testExtension1() → dynamic
+  ;
+static method testExtension2() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect
new file mode 100644
index 0000000..be0799d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect
@@ -0,0 +1,101 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+  core::print("Extension1.method on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+  core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int* {
+  core::print("Extension2.method on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(2);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+  core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(3) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+  self::testExtension1();
+  self::testExtension2();
+}
+static method testExtension1() → dynamic {
+  self::Class1* c0 = new self::Class1::•(0);
+  self::Class1* c1 = new self::Class1::•(1);
+  () →* core::int* tearOff0 = self::Extension1|get#method(c0);
+  self::expect(0, tearOff0.call());
+  c0 = new self::Class1::•(4.{core::int::unary-}());
+  self::expect(0, tearOff0.call());
+  () →* core::int* tearOff1 = self::Extension1|get#method(c1);
+  self::expect(1, tearOff1.call());
+  c1 = new self::Class1::•(7.{core::int::unary-}());
+  self::expect(1, tearOff1.call());
+  <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension1|get#genericMethod(c0);
+  self::expect(38, genericTearOff0.call<core::int*>(42));
+  self::expect(38, genericTearOff0.call<core::num*>(42));
+  <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c1);
+  self::expect(35, genericTearOff1.call<core::int*>(42));
+  self::expect(35, genericTearOff1.call<core::num*>(42));
+}
+static method testExtension2() → dynamic {
+  self::Class2* c0 = new self::Class2::•(0);
+  self::Class2* c1 = new self::Class2::•(1);
+  () →* core::int* tearOff0 = self::Extension2|get#method(c0);
+  self::expect(2, tearOff0.call());
+  c0 = new self::Class2::•(4.{core::int::unary-}());
+  self::expect(2, tearOff0.call());
+  () →* core::int* tearOff1 = self::Extension2|get#method(c1);
+  self::expect(3, tearOff1.call());
+  c1 = new self::Class2::•(7.{core::int::unary-}());
+  self::expect(3, tearOff1.call());
+  <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension2|get#genericMethod(c0);
+  self::expect(41, genericTearOff0.call<core::int*>(42));
+  self::expect(41, genericTearOff0.call<core::num*>(42));
+  <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension2|get#genericMethod(c1);
+  self::expect(38, genericTearOff1.call<core::int*>(42));
+  self::expect(38, genericTearOff1.call<core::num*>(42));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect
new file mode 100644
index 0000000..be0799d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect
@@ -0,0 +1,101 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class1*
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+  field core::int* field;
+  constructor •(core::int* field) → self::Class2*
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  method toString() → core::String*
+    return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+  method method = self::Extension1|method;
+  tearoff method = self::Extension1|get#method;
+  method genericMethod = self::Extension1|genericMethod;
+  tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+  method method = self::Extension2|method;
+  tearoff method = self::Extension2|get#method;
+  method genericMethod = self::Extension2|genericMethod;
+  tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+  core::print("Extension1.method on ${#this}");
+  return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+  return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+  core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int* {
+  core::print("Extension2.method on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(2);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+  return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+  core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+  return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(3) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+  return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+  self::testExtension1();
+  self::testExtension2();
+}
+static method testExtension1() → dynamic {
+  self::Class1* c0 = new self::Class1::•(0);
+  self::Class1* c1 = new self::Class1::•(1);
+  () →* core::int* tearOff0 = self::Extension1|get#method(c0);
+  self::expect(0, tearOff0.call());
+  c0 = new self::Class1::•(4.{core::int::unary-}());
+  self::expect(0, tearOff0.call());
+  () →* core::int* tearOff1 = self::Extension1|get#method(c1);
+  self::expect(1, tearOff1.call());
+  c1 = new self::Class1::•(7.{core::int::unary-}());
+  self::expect(1, tearOff1.call());
+  <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension1|get#genericMethod(c0);
+  self::expect(38, genericTearOff0.call<core::int*>(42));
+  self::expect(38, genericTearOff0.call<core::num*>(42));
+  <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c1);
+  self::expect(35, genericTearOff1.call<core::int*>(42));
+  self::expect(35, genericTearOff1.call<core::num*>(42));
+}
+static method testExtension2() → dynamic {
+  self::Class2* c0 = new self::Class2::•(0);
+  self::Class2* c1 = new self::Class2::•(1);
+  () →* core::int* tearOff0 = self::Extension2|get#method(c0);
+  self::expect(2, tearOff0.call());
+  c0 = new self::Class2::•(4.{core::int::unary-}());
+  self::expect(2, tearOff0.call());
+  () →* core::int* tearOff1 = self::Extension2|get#method(c1);
+  self::expect(3, tearOff1.call());
+  c1 = new self::Class2::•(7.{core::int::unary-}());
+  self::expect(3, tearOff1.call());
+  <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension2|get#genericMethod(c0);
+  self::expect(41, genericTearOff0.call<core::int*>(42));
+  self::expect(41, genericTearOff0.call<core::num*>(42));
+  <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension2|get#genericMethod(c1);
+  self::expect(38, genericTearOff1.call<core::int*>(42));
+  self::expect(38, genericTearOff1.call<core::num*>(42));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect
new file mode 100644
index 0000000..675c36c
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect
@@ -0,0 +1,12 @@
+pkg/front_end/testcases/extensions/instance_tearoff.dart:54:6: Context: Write to c0@978
+  c0 = new Class1(-4);
+     ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:58:6: Context: Write to c1@1007
+  c1 = new Class1(-7);
+     ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:73:6: Context: Write to c0@1494
+  c0 = new Class2(-4);
+     ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:77:6: Context: Write to c1@1523
+  c1 = new Class2(-7);
+     ^
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart
new file mode 100644
index 0000000..5210e3a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {}
+
+extension Extension on Class {
+  method(a) {}
+}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+  method() {}
+}
+
+
+
+main() {
+  String s = '';
+
+  Class c1 = new Class();
+  Extension().method(null);
+  Extension(c1, null).method(null);
+  Extension(receiver: c1).method(null);
+  Extension(c1, receiver: null).method(null);
+  Extension<int>(c1).method(null);
+  Extension(s).method(null);
+  Extension(c1).foo;
+  Extension(c1).foo = null;
+  Extension(c1).foo();
+  Extension(c1).method();
+  // TODO(johnniwinther): Report argument/parameter count corresponding to
+  // the source code/declaration, not the converted invocation.
+  // TODO(johnniwinther): Use the declaration name length for the squiggly.
+  Extension(c1).method(1, 2);
+  Extension(c1).method(a: 1);
+  Extension(c1).method(1, a: 2);
+  Extension(c1).method<int>(null);
+
+  GenericClass<int> c2 = new GenericClass<int>();
+  GenericExtension().method();
+  GenericExtension<int>().method();
+  GenericExtension(c2, null).method();
+  GenericExtension<int>(c2, null).method();
+  GenericExtension(receiver: c2).method();
+  GenericExtension<int>(receiver: c2).method();
+  GenericExtension(c2, receiver: null).method();
+  GenericExtension<int>(c2, receiver: null).method();
+  GenericExtension<int, String>(c2).method();
+  GenericExtension(s).method();
+  GenericExtension<int>(s).method();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect
new file mode 100644
index 0000000..ff612da
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    ;
+}
+extension Extension on self::Class* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic
+  ;
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic
+  ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect
new file mode 100644
index 0000000..b24b206
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect
@@ -0,0 +1,240 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension().method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(c1, null).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(receiver: c1).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(c1, receiver: null).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+//   Extension<int>(c1).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+//   Extension(c1).foo;
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+//   Extension(c1).foo = null;
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+//   Extension(c1).foo();
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+//   Extension(c1).method();
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//   Extension(c1).method(1, 2);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+//   Extension(c1).method(a: 1);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+//   Extension(c1).method(1, a: 2);
+//                           ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+//   Extension(c1).method<int>(null);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension().method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>().method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(c2, null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(c2, null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(receiver: c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(receiver: c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(c2, receiver: null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(c2, receiver: null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+//   GenericExtension<int, String>(c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'Class'.
+//   Extension(s).method(null);
+//             ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+//  - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+//   GenericExtension(s).method();
+//                    ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+//  - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+//   GenericExtension<int>(s).method();
+//                         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic {}
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic {}
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic {
+  core::String* s = "";
+  self::Class* c1 = new self::Class::•();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension().method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(c1, null).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(receiver: c1).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(c1, receiver: null).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+  Extension<int>(c1).method(null);
+  ^^^^^^^^^".method(null);
+  self::Extension|method(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'Class'.
+  Extension(s).method(null);
+            ^" in s as{TypeError} self::Class*, null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+  Extension(c1).foo;
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+  Extension(c1).foo = null;
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+  Extension(c1).foo();
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+  Extension(c1).method();
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+  Extension(c1).method(1, 2);
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+  Extension(c1).method(a: 1);
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+  Extension(c1).method(1, a: 2);
+                          ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+  Extension(c1).method<int>(null);
+  ^";
+  self::GenericClass<core::int*>* c2 = new self::GenericClass::•<core::int*>();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension().method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>().method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(c2, null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(c2, null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(receiver: c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(receiver: c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(c2, receiver: null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(c2, receiver: null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+  GenericExtension<int, String>(c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  self::GenericExtension|method<dynamic>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+  GenericExtension(s).method();
+                   ^" in s as{TypeError} self::GenericClass<dynamic>*);
+  self::GenericExtension|method<core::int*>(let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+  GenericExtension<int>(s).method();
+                        ^" in s as{TypeError} self::GenericClass<core::int*>*);
+}
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..b24b206
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect
@@ -0,0 +1,240 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension().method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(c1, null).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(receiver: c1).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   Extension(c1, receiver: null).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+//   Extension<int>(c1).method(null);
+//   ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+//   Extension(c1).foo;
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+//   Extension(c1).foo = null;
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+//   Extension(c1).foo();
+//   ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+//   Extension(c1).method();
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//   Extension(c1).method(1, 2);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+//   Extension(c1).method(a: 1);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+//   Extension(c1).method(1, a: 2);
+//                           ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+//   Extension(c1).method<int>(null);
+//   ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   method(a) {}
+//   ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension().method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>().method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(c2, null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(c2, null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(receiver: c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(receiver: c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension(c2, receiver: null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+//   GenericExtension<int>(c2, receiver: null).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+//   GenericExtension<int, String>(c2).method();
+//   ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'Class'.
+//   Extension(s).method(null);
+//             ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+//  - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+//   GenericExtension(s).method();
+//                    ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+//  - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+//   GenericExtension<int>(s).method();
+//                         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+  method method = self::GenericExtension|method;
+  tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic {}
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+  return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic {}
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic {
+  core::String* s = "";
+  self::Class* c1 = new self::Class::•();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension().method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(c1, null).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(receiver: c1).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+  Extension(c1, receiver: null).method(null);
+  ^^^^^^^^^".method(null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+  Extension<int>(c1).method(null);
+  ^^^^^^^^^".method(null);
+  self::Extension|method(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'Class'.
+  Extension(s).method(null);
+            ^" in s as{TypeError} self::Class*, null);
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+  Extension(c1).foo;
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+  Extension(c1).foo = null;
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+  Extension(c1).foo();
+  ^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+  Extension(c1).method();
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+  Extension(c1).method(1, 2);
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+  Extension(c1).method(a: 1);
+  ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+  Extension(c1).method(1, a: 2);
+                          ^";
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+  Extension(c1).method<int>(null);
+  ^";
+  self::GenericClass<core::int*>* c2 = new self::GenericClass::•<core::int*>();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension().method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>().method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(c2, null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(c2, null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(receiver: c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(receiver: c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension(c2, receiver: null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+  GenericExtension<int>(c2, receiver: null).method();
+  ^^^^^^^^^^^^^^^^".method();
+  invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+  GenericExtension<int, String>(c2).method();
+  ^^^^^^^^^^^^^^^^".method();
+  self::GenericExtension|method<dynamic>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+  GenericExtension(s).method();
+                   ^" in s as{TypeError} self::GenericClass<dynamic>*);
+  self::GenericExtension|method<core::int*>(let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+  GenericExtension<int>(s).method();
+                        ^" in s as{TypeError} self::GenericClass<core::int*>*);
+}
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart b/pkg/front_end/testcases/extensions/nested_on_types.dart
new file mode 100644
index 0000000..f0cbdc1
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A<T> {}
+
+extension Extension<T> on A<A<T>> {
+  method1() {}
+
+  method2<A>(A a) {}
+}
+
+main() {
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect
new file mode 100644
index 0000000..dae6f4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T*>*
+    ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic
+  ;
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic
+  ;
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+  return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect
new file mode 100644
index 0000000..6a8c1f4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T*>*
+    : super core::Object::•()
+    ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic {}
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic {}
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+  return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect
new file mode 100644
index 0000000..6a8c1f4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T*>*
+    : super core::Object::•()
+    ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic {}
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+  return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic {}
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+  return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart b/pkg/front_end/testcases/extensions/on_type_inference.dart
new file mode 100644
index 0000000..2cce0dc
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+extension BestCom<T extends num> on Iterable<T> {
+  T best() => null;
+}
+extension BestList<T> on List<T> {
+  T best() => null;
+}
+extension BestSpec on List<num> {
+ num best() => null;
+}
+
+main() {
+  List<int> x;
+  var v = x.best();
+  List<num> y;
+  var w = y.best();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect
new file mode 100644
index 0000000..a4e1d3c
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+  method best = self::BestCom|best;
+  tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+  method best = self::BestList|best;
+  tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+  method best = self::BestSpec|best;
+  tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+  ;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+  return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+  ;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+  return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+  ;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+  return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect
new file mode 100644
index 0000000..25a3e4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+  method best = self::BestCom|best;
+  tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+  method best = self::BestList|best;
+  tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+  method best = self::BestSpec|best;
+  tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+  return null;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+  return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+  return null;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+  return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+  return null;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+  return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic {
+  core::List<core::int*>* x;
+  core::int* v = self::BestList|best<core::int*>(x);
+  core::List<core::num*>* y;
+  core::num* w = self::BestSpec|best(y);
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..25a3e4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+  method best = self::BestCom|best;
+  tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+  method best = self::BestList|best;
+  tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+  method best = self::BestSpec|best;
+  tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+  return null;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+  return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+  return null;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+  return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+  return null;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+  return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic {
+  core::List<core::int*>* x;
+  core::int* v = self::BestList|best<core::int*>(x);
+  core::List<core::num*>* y;
+  core::num* w = self::BestSpec|best(y);
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart
new file mode 100644
index 0000000..a56cd04
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Struct {}
+
+class StructA extends Struct {}
+
+class StructB extends Struct {}
+
+class NonStruct {}
+
+extension Extension<T extends Struct> on T {
+  T method() => this;
+  T get property => this;
+  void set property(T value) {}
+}
+
+main() {
+  Struct struct;
+  StructA structA;
+  StructB structB;
+
+  struct.method();
+  struct.property = structA.property;
+  structA.method();
+  structA.property = struct.property;
+  structB.method();
+  structB.property = structB.property;
+
+  new Struct().method();
+  new Struct().property;
+  new Struct().property = null;
+  new StructA().method();
+  new StructA().property;
+  new StructA().property = null;
+  new StructB().method();
+  new StructB().property;
+  new StructB().property = null;
+}
+
+testNonStruct() {
+  NonStruct nonStruct;
+  nonStruct.method();
+  nonStruct.property = nonStruct.property;
+  new NonStruct().method();
+  new NonStruct().property;
+  new NonStruct().property = null;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect
new file mode 100644
index 0000000..2cb9786
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+  synthetic constructor •() → self::Struct*
+    ;
+}
+class StructA extends self::Struct {
+  synthetic constructor •() → self::StructA*
+    ;
+}
+class StructB extends self::Struct {
+  synthetic constructor •() → self::StructB*
+    ;
+}
+class NonStruct extends core::Object {
+  synthetic constructor •() → self::NonStruct*
+    ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+  get property = self::Extension|get#property;
+  set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+  ;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+  return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+  ;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → void
+  ;
+static method main() → dynamic
+  ;
+static method testNonStruct() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect
new file mode 100644
index 0000000..7860276
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect
@@ -0,0 +1,127 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   nonStruct.method();
+//             ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+//   nonStruct.property = nonStruct.property;
+//             ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:34: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   nonStruct.property = nonStruct.property;
+//                                  ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   new NonStruct().method();
+//                   ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   new NonStruct().property;
+//                   ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+//   new NonStruct().property = null;
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+  synthetic constructor •() → self::Struct*
+    : super core::Object::•()
+    ;
+}
+class StructA extends self::Struct {
+  synthetic constructor •() → self::StructA*
+    : super self::Struct::•()
+    ;
+}
+class StructB extends self::Struct {
+  synthetic constructor •() → self::StructB*
+    : super self::Struct::•()
+    ;
+}
+class NonStruct extends core::Object {
+  synthetic constructor •() → self::NonStruct*
+    : super core::Object::•()
+    ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+  get property = self::Extension|get#property;
+  set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+  return #this;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+  return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+  return #this;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → self::Extension|set#property::T* {
+  final self::Extension|set#property::T* #t1 = value;
+  return #t1;
+}
+static method main() → dynamic {
+  self::Struct* struct;
+  self::StructA* structA;
+  self::StructB* structB;
+  self::Extension|method<self::Struct*>(struct);
+  self::Extension|set#property<self::Struct*>(struct, self::Extension|get#property<self::StructA*>(structA));
+  self::Extension|method<self::StructA*>(structA);
+  self::Extension|set#property<self::StructA*>(structA, self::Extension|get#property<self::Struct*>(struct));
+  self::Extension|method<self::StructB*>(structB);
+  self::Extension|set#property<self::StructB*>(structB, self::Extension|get#property<self::StructB*>(structB));
+  self::Extension|method<self::Struct*>(new self::Struct::•());
+  self::Extension|get#property<self::Struct*>(new self::Struct::•());
+  self::Extension|set#property<self::Struct*>(new self::Struct::•(), null);
+  self::Extension|method<self::StructA*>(new self::StructA::•());
+  self::Extension|get#property<self::StructA*>(new self::StructA::•());
+  self::Extension|set#property<self::StructA*>(new self::StructA::•(), null);
+  self::Extension|method<self::StructB*>(new self::StructB::•());
+  self::Extension|get#property<self::StructB*>(new self::StructB::•());
+  self::Extension|set#property<self::StructB*>(new self::StructB::•(), null);
+}
+static method testNonStruct() → dynamic {
+  self::NonStruct* nonStruct;
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  nonStruct.method();
+            ^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+  nonStruct.property = nonStruct.property;
+            ^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  new NonStruct().method();
+                  ^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+  new NonStruct().property;
+                  ^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+  new NonStruct().property = null;
+                  ^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..7860276
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect
@@ -0,0 +1,127 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   nonStruct.method();
+//             ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+//   nonStruct.property = nonStruct.property;
+//             ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:34: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   nonStruct.property = nonStruct.property;
+//                                  ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   new NonStruct().method();
+//                   ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   new NonStruct().property;
+//                   ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+//  - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+//   new NonStruct().property = null;
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+  synthetic constructor •() → self::Struct*
+    : super core::Object::•()
+    ;
+}
+class StructA extends self::Struct {
+  synthetic constructor •() → self::StructA*
+    : super self::Struct::•()
+    ;
+}
+class StructB extends self::Struct {
+  synthetic constructor •() → self::StructB*
+    : super self::Struct::•()
+    ;
+}
+class NonStruct extends core::Object {
+  synthetic constructor •() → self::NonStruct*
+    : super core::Object::•()
+    ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+  method method = self::Extension|method;
+  tearoff method = self::Extension|get#method;
+  get property = self::Extension|get#property;
+  set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+  return #this;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+  return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+  return #this;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → self::Extension|set#property::T* {
+  final self::Extension|set#property::T* #t1 = value;
+  return #t1;
+}
+static method main() → dynamic {
+  self::Struct* struct;
+  self::StructA* structA;
+  self::StructB* structB;
+  self::Extension|method<self::Struct*>(struct);
+  self::Extension|set#property<self::Struct*>(struct, self::Extension|get#property<self::StructA*>(structA));
+  self::Extension|method<self::StructA*>(structA);
+  self::Extension|set#property<self::StructA*>(structA, self::Extension|get#property<self::Struct*>(struct));
+  self::Extension|method<self::StructB*>(structB);
+  self::Extension|set#property<self::StructB*>(structB, self::Extension|get#property<self::StructB*>(structB));
+  self::Extension|method<self::Struct*>(new self::Struct::•());
+  self::Extension|get#property<self::Struct*>(new self::Struct::•());
+  self::Extension|set#property<self::Struct*>(new self::Struct::•(), null);
+  self::Extension|method<self::StructA*>(new self::StructA::•());
+  self::Extension|get#property<self::StructA*>(new self::StructA::•());
+  self::Extension|set#property<self::StructA*>(new self::StructA::•(), null);
+  self::Extension|method<self::StructB*>(new self::StructB::•());
+  self::Extension|get#property<self::StructB*>(new self::StructB::•());
+  self::Extension|set#property<self::StructB*>(new self::StructB::•(), null);
+}
+static method testNonStruct() → dynamic {
+  self::NonStruct* nonStruct;
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  nonStruct.method();
+            ^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+  nonStruct.property = nonStruct.property;
+            ^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  new NonStruct().method();
+                  ^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+  new NonStruct().property;
+                  ^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+  new NonStruct().property = null;
+                  ^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart b/pkg/front_end/testcases/extensions/operators.dart
new file mode 100644
index 0000000..cbb3b41
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Complex {
+  final double real;
+  final double imaginary;
+
+  const Complex(this.real, this.imaginary);
+
+  Complex add(Complex other) {
+    return new Complex(real + other.real, imaginary + other.imaginary);
+  }
+
+  Complex sub(Complex other) {
+    return new Complex(real - other.real, imaginary - other.imaginary);
+  }
+
+  Complex negate() {
+    return new Complex(-real, -imaginary);
+  }
+
+  int get hashCode => real.hashCode * 13 + imaginary.hashCode * 19;
+
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is Complex &&
+        real == other.real &&
+        imaginary == other.imaginary;
+  }
+
+  String toString() => 'Complex($real,$imaginary)';
+}
+
+extension Operators on Complex {
+  Complex operator +(Complex other) => add(other);
+  Complex operator -(Complex other) => sub(other);
+  Complex operator -() => negate();
+}
+
+main() {
+  Complex c_m2 = new Complex(-2, 2);
+  Complex c_m1 = new Complex(-1, 1);
+  Complex c0 = new Complex(0, 0);
+  Complex c1 = new Complex(1, -1);
+  Complex c2 = new Complex(2, -2);
+
+  expect(c_m2, c0 + c_m2);
+  expect(c_m2, c_m2 + c0);
+  expect(c_m2, c_m1 + c_m1);
+  expect(c_m1, c0 + c_m1);
+  expect(c_m1, c_m1 + c0);
+  expect(c0, c_m2 + c2);
+  expect(c0, c2 + c_m2);
+  expect(c0, c_m1 + c1);
+  expect(c0, c1 + c_m1);
+  expect(c0, c0 + c0);
+  expect(c1, c0 + c1);
+  expect(c1, c1 + c0);
+  expect(c2, c0 + c2);
+  expect(c2, c2 + c0);
+  expect(c2, c1 + c1);
+
+  expect(c_m2, c0 - c2);
+  expect(c2, c2 - c0);
+  expect(c_m2, -c2);
+  expect(c_m1, c1 - c2);
+  expect(c1, c2 - c1);
+  expect(c_m1, c0 - c1);
+  expect(c1, c1 - c0);
+  expect(c_m1, -c1);
+  expect(c0, c2 - c2);
+  expect(c0, c1 - c1);
+  expect(c0, c0 - c0);
+  expect(c0, c_m1 - c_m1);
+  expect(c0, c_m2 - c_m2);
+  expect(c0, -c0);
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/operators.dart.outline.expect b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
new file mode 100644
index 0000000..bfa897a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+  final field core::double* real;
+  final field core::double* imaginary;
+  const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+    : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+    ;
+  method add(self::Complex* other) → self::Complex*
+    ;
+  method sub(self::Complex* other) → self::Complex*
+    ;
+  method negate() → self::Complex*
+    ;
+  get hashCode() → core::int*
+    ;
+  operator ==(core::Object* other) → core::bool*
+    ;
+  method toString() → core::String*
+    ;
+}
+extension Operators on self::Complex* {
+  operator + = self::Operators|+;
+  operator - = self::Operators|-;
+  operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+  ;
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+  ;
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
new file mode 100644
index 0000000..936cc18
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
@@ -0,0 +1,81 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+  final field core::double* real;
+  final field core::double* imaginary;
+  const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+    : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+    ;
+  method add(self::Complex* other) → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::+}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::+}(other.{self::Complex::imaginary}));
+  }
+  method sub(self::Complex* other) → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::-}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::-}(other.{self::Complex::imaginary}));
+  }
+  method negate() → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::unary-}(), this.{self::Complex::imaginary}.{core::double::unary-}());
+  }
+  get hashCode() → core::int*
+    return this.{self::Complex::real}.{core::num::hashCode}.{core::num::*}(13).{core::num::+}(this.{self::Complex::imaginary}.{core::num::hashCode}.{core::num::*}(19));
+  operator ==(core::Object* other) → core::bool* {
+    if(core::identical(this, other))
+      return true;
+    return other is self::Complex* && this.{self::Complex::real}.{core::num::==}(other{self::Complex*}.{self::Complex::real}) && this.{self::Complex::imaginary}.{core::num::==}(other{self::Complex*}.{self::Complex::imaginary});
+  }
+  method toString() → core::String*
+    return "Complex(${this.{self::Complex::real}},${this.{self::Complex::imaginary}})";
+}
+extension Operators on self::Complex* {
+  operator + = self::Operators|+;
+  operator - = self::Operators|-;
+  operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+  return #this.{self::Complex::add}(other);
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+  return #this.{self::Complex::sub}(other);
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+  return #this.{self::Complex::negate}();
+static method main() → dynamic {
+  self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+  self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+  self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+  self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+  self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+  self::expect(c_m2, self::Operators|+(c0, c_m2));
+  self::expect(c_m2, self::Operators|+(c_m2, c0));
+  self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+  self::expect(c_m1, self::Operators|+(c0, c_m1));
+  self::expect(c_m1, self::Operators|+(c_m1, c0));
+  self::expect(c0, self::Operators|+(c_m2, c2));
+  self::expect(c0, self::Operators|+(c2, c_m2));
+  self::expect(c0, self::Operators|+(c_m1, c1));
+  self::expect(c0, self::Operators|+(c1, c_m1));
+  self::expect(c0, self::Operators|+(c0, c0));
+  self::expect(c1, self::Operators|+(c0, c1));
+  self::expect(c1, self::Operators|+(c1, c0));
+  self::expect(c2, self::Operators|+(c0, c2));
+  self::expect(c2, self::Operators|+(c2, c0));
+  self::expect(c2, self::Operators|+(c1, c1));
+  self::expect(c_m2, self::Operators|-(c0, c2));
+  self::expect(c2, self::Operators|-(c2, c0));
+  self::expect(c_m2, self::Operators|unary-(c2));
+  self::expect(c_m1, self::Operators|-(c1, c2));
+  self::expect(c1, self::Operators|-(c2, c1));
+  self::expect(c_m1, self::Operators|-(c0, c1));
+  self::expect(c1, self::Operators|-(c1, c0));
+  self::expect(c_m1, self::Operators|unary-(c1));
+  self::expect(c0, self::Operators|-(c2, c2));
+  self::expect(c0, self::Operators|-(c1, c1));
+  self::expect(c0, self::Operators|-(c0, c0));
+  self::expect(c0, self::Operators|-(c_m1, c_m1));
+  self::expect(c0, self::Operators|-(c_m2, c_m2));
+  self::expect(c0, self::Operators|unary-(c0));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
new file mode 100644
index 0000000..936cc18
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
@@ -0,0 +1,81 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+  final field core::double* real;
+  final field core::double* imaginary;
+  const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+    : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+    ;
+  method add(self::Complex* other) → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::+}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::+}(other.{self::Complex::imaginary}));
+  }
+  method sub(self::Complex* other) → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::-}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::-}(other.{self::Complex::imaginary}));
+  }
+  method negate() → self::Complex* {
+    return new self::Complex::•(this.{self::Complex::real}.{core::double::unary-}(), this.{self::Complex::imaginary}.{core::double::unary-}());
+  }
+  get hashCode() → core::int*
+    return this.{self::Complex::real}.{core::num::hashCode}.{core::num::*}(13).{core::num::+}(this.{self::Complex::imaginary}.{core::num::hashCode}.{core::num::*}(19));
+  operator ==(core::Object* other) → core::bool* {
+    if(core::identical(this, other))
+      return true;
+    return other is self::Complex* && this.{self::Complex::real}.{core::num::==}(other{self::Complex*}.{self::Complex::real}) && this.{self::Complex::imaginary}.{core::num::==}(other{self::Complex*}.{self::Complex::imaginary});
+  }
+  method toString() → core::String*
+    return "Complex(${this.{self::Complex::real}},${this.{self::Complex::imaginary}})";
+}
+extension Operators on self::Complex* {
+  operator + = self::Operators|+;
+  operator - = self::Operators|-;
+  operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+  return #this.{self::Complex::add}(other);
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+  return #this.{self::Complex::sub}(other);
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+  return #this.{self::Complex::negate}();
+static method main() → dynamic {
+  self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+  self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+  self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+  self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+  self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+  self::expect(c_m2, self::Operators|+(c0, c_m2));
+  self::expect(c_m2, self::Operators|+(c_m2, c0));
+  self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+  self::expect(c_m1, self::Operators|+(c0, c_m1));
+  self::expect(c_m1, self::Operators|+(c_m1, c0));
+  self::expect(c0, self::Operators|+(c_m2, c2));
+  self::expect(c0, self::Operators|+(c2, c_m2));
+  self::expect(c0, self::Operators|+(c_m1, c1));
+  self::expect(c0, self::Operators|+(c1, c_m1));
+  self::expect(c0, self::Operators|+(c0, c0));
+  self::expect(c1, self::Operators|+(c0, c1));
+  self::expect(c1, self::Operators|+(c1, c0));
+  self::expect(c2, self::Operators|+(c0, c2));
+  self::expect(c2, self::Operators|+(c2, c0));
+  self::expect(c2, self::Operators|+(c1, c1));
+  self::expect(c_m2, self::Operators|-(c0, c2));
+  self::expect(c2, self::Operators|-(c2, c0));
+  self::expect(c_m2, self::Operators|unary-(c2));
+  self::expect(c_m1, self::Operators|-(c1, c2));
+  self::expect(c1, self::Operators|-(c2, c1));
+  self::expect(c_m1, self::Operators|-(c0, c1));
+  self::expect(c1, self::Operators|-(c1, c0));
+  self::expect(c_m1, self::Operators|unary-(c1));
+  self::expect(c0, self::Operators|-(c2, c2));
+  self::expect(c0, self::Operators|-(c1, c1));
+  self::expect(c0, self::Operators|-(c0, c0));
+  self::expect(c0, self::Operators|-(c_m1, c_m1));
+  self::expect(c0, self::Operators|-(c_m2, c_m2));
+  self::expect(c0, self::Operators|unary-(c0));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect
new file mode 100644
index 0000000..0cf24a9
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/extensions/operators.dart:27:18: Context: Possible promotion of other@348
+    return other is Complex &&
+                 ^^
diff --git a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
index 6b24546..4c4e60c 100644
--- a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
@@ -30,8 +30,10 @@
 static field core::int* A2|staticField = self::A1::getStaticField();
 static method A2|get#instanceProperty(final self::A1* #this) → core::int*
   return #this.{self::A1::getInstanceField}();
-static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → void {
+static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
   #this.{self::A1::setInstanceField}(value);
+  return #t1;
 }
 static method A2|+(final self::A1* #this, core::int* value) → core::int* {
   return #this.{self::A1::getInstanceField}().{core::num::+}(value);
diff --git a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
index 6b24546..4c4e60c 100644
--- a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
@@ -30,8 +30,10 @@
 static field core::int* A2|staticField = self::A1::getStaticField();
 static method A2|get#instanceProperty(final self::A1* #this) → core::int*
   return #this.{self::A1::getInstanceField}();
-static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → void {
+static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → core::int* {
+  final core::int* #t1 = value;
   #this.{self::A1::setInstanceField}(value);
+  return #t1;
 }
 static method A2|+(final self::A1* #this, core::int* value) → core::int* {
   return #this.{self::A1::getInstanceField}().{core::num::+}(value);
diff --git a/pkg/front_end/testcases/extensions/static_access.dart b/pkg/front_end/testcases/extensions/static_access.dart
index c31ac01..170f77e 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart
+++ b/pkg/front_end/testcases/extensions/static_access.dart
@@ -10,6 +10,10 @@
   static get property => 42;
   static set property(value) {}
   static var field;
+
+  instanceMethod() {}
+  get instanceProperty => 42;
+  set instanceProperty(value) {}
 }
 
 main() {
@@ -22,4 +26,4 @@
   Extension.property = 42;
   Extension.field;
   Extension.field = 42;
-}
\ No newline at end of file
+}
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.outline.expect b/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
index 4e9dc86..840ecf2 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
@@ -11,7 +11,11 @@
   static method genericMethod = self::Extension|genericMethod;
   static get property = get self::Extension|property;
   static field field = self::Extension|field;
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
   static set property = set self::Extension|property;
+  set instanceProperty = self::Extension|set#instanceProperty;
 }
 static field dynamic Extension|field;
 static method Extension|method() → dynamic
@@ -22,5 +26,13 @@
   ;
 static set Extension|property(dynamic value) → void
   ;
+static method Extension|instanceMethod(final self::Class* #this) → dynamic
+  ;
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  ;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → void
+  ;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.strong.expect b/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
index 9056365..9c616d4 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
@@ -12,7 +12,11 @@
   static method genericMethod = self::Extension|genericMethod;
   static get property = get self::Extension|property;
   static field field = self::Extension|field;
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
   static set property = set self::Extension|property;
+  set instanceProperty = self::Extension|set#instanceProperty;
 }
 static field dynamic Extension|field;
 static method Extension|method() → dynamic {}
@@ -20,6 +24,15 @@
 static get Extension|property() → dynamic
   return 42;
 static set Extension|property(dynamic value) → void {}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
+  return #t1;
+}
 static method main() → dynamic {
   self::Extension|method();
   self::Extension|genericMethod<core::int*>(42);
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
index 9056365..9c616d4 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
@@ -12,7 +12,11 @@
   static method genericMethod = self::Extension|genericMethod;
   static get property = get self::Extension|property;
   static field field = self::Extension|field;
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
   static set property = set self::Extension|property;
+  set instanceProperty = self::Extension|set#instanceProperty;
 }
 static field dynamic Extension|field;
 static method Extension|method() → dynamic {}
@@ -20,6 +24,15 @@
 static get Extension|property() → dynamic
   return 42;
 static set Extension|property(dynamic value) → void {}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
+  return #t1;
+}
 static method main() → dynamic {
   self::Extension|method();
   self::Extension|genericMethod<core::int*>(42);
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart b/pkg/front_end/testcases/extensions/static_access_of_instance.dart
new file mode 100644
index 0000000..606a735
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {}
+
+extension Extension on Class {
+  instanceMethod() {}
+  get instanceProperty => 42;
+  set instanceProperty(value) {}
+}
+
+main() {
+  Extension.instanceMethod();
+  Extension.instanceMethod;
+  Extension.instanceProperty;
+  Extension.instanceProperty = 42;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect
new file mode 100644
index 0000000..0578511
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    ;
+}
+extension Extension on self::Class* {
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
+  set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic
+  ;
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  ;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → void
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect
new file mode 100644
index 0000000..10c2dbb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+//   Extension.instanceMethod();
+//             ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+//   Extension.instanceMethod;
+//             ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+//   Extension.instanceProperty;
+//             ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+//   Extension.instanceProperty = 42;
+//             ^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
+  set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
+  return #t1;
+}
+static method main() → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+  Extension.instanceMethod();
+            ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+  Extension.instanceMethod;
+            ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+  Extension.instanceProperty;
+            ^^^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+  Extension.instanceProperty = 42;
+            ^^^^^^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect
new file mode 100644
index 0000000..10c2dbb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+//   Extension.instanceMethod();
+//             ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+//   Extension.instanceMethod;
+//             ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+//   Extension.instanceProperty;
+//             ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+//   Extension.instanceProperty = 42;
+//             ^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method instanceMethod = self::Extension|instanceMethod;
+  tearoff instanceMethod = self::Extension|get#instanceMethod;
+  get instanceProperty = self::Extension|get#instanceProperty;
+  set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+  return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+  return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+  final dynamic #t1 = value;
+  return #t1;
+}
+static method main() → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+  Extension.instanceMethod();
+            ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+  Extension.instanceMethod;
+            ^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+  Extension.instanceProperty;
+            ^^^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+  Extension.instanceProperty = 42;
+            ^^^^^^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart b/pkg/front_end/testcases/extensions/type_variables.dart
index 0f784b7..bea2ded 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart
+++ b/pkg/front_end/testcases/extensions/type_variables.dart
@@ -9,8 +9,6 @@
     return this;
   }
 
-  // TODO(johnniwinther): Resolve type variable uses correctly. Currently use
-  // `T` here resolve to `A2.T` and the synthetically inserted type variable.
   A1<T> method2<S extends A1<T>>(S o) {
     print(o);
     print(T);
@@ -19,7 +17,11 @@
   }
 }
 
-// TODO(johnniwinther): Support F-bounded extensions. Currently the type
-// variable is not recognized as a type within the bound.
+extension A3<T extends A1<T>> on A1<T> {
+}
+
+extension A4<T> on A1<T> {
+  method<T>() {}
+}
 
 main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect b/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
index 3689d95..862daf8 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
@@ -8,11 +8,27 @@
 }
 extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>*
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+  method method = self::A4|method;
+  tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>*
   ;
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>*
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+  return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>*
   ;
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+  return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic
+  ;
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+  return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect b/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
index 4f6a8d5..27f3e58 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
@@ -9,15 +9,30 @@
 }
 extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>* {
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+  method method = self::A4|method;
+  tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>* {
   return #this;
 }
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>* {
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+  return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>* {
   core::print(o);
-  core::print(self::A2|method2::#T*);
+  core::print(self::A2|method2::T*);
   core::print(self::A2|method2::S*);
   return #this;
 }
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+  return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic {}
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+  return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
index 4f6a8d5..27f3e58 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
@@ -9,15 +9,30 @@
 }
 extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>* {
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+  method method = self::A4|method;
+  tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>* {
   return #this;
 }
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>* {
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+  return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>* {
   core::print(o);
-  core::print(self::A2|method2::#T*);
+  core::print(self::A2|method2::T*);
   core::print(self::A2|method2::S*);
   return #this;
 }
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+  return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic {}
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+  return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.outline.expect b/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
index dbd8b2e..76a98246 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
@@ -12,19 +12,31 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1*
   ;
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1*
   ;
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>*
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>*
   ;
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>*
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>*
   ;
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.strong.expect b/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
index 442c519..31c3f25 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
@@ -14,24 +14,36 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1* {
   return #this;
 }
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
   core::print(o);
   return #this;
 }
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
   return #this;
 }
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
   core::print(o);
   return #this;
 }
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
index 442c519..31c3f25 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
@@ -14,24 +14,36 @@
 }
 extension A2 on self::A1* {
   method method1 = self::A2|method1;
+  tearoff method1 = self::A2|get#method1;
   method method2 = self::A2|method2;
+  tearoff method2 = self::A2|get#method2;
 }
 extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
   method method1 = self::B2|method1;
+  tearoff method1 = self::B2|get#method1;
   method method2 = self::B2|method2;
+  tearoff method2 = self::B2|get#method2;
 }
 static method A2|method1(final self::A1* #this) → self::A1* {
   return #this;
 }
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+  return () → self::A1* => self::A2|method1(#this);
 static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
   core::print(o);
   return #this;
 }
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+  return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
   return #this;
 }
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+  return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
   core::print(o);
   return #this;
 }
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+  return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/bug37476.dart b/pkg/front_end/testcases/general/bug37476.dart
index 4483ee2..53a6f0d 100644
--- a/pkg/front_end/testcases/general/bug37476.dart
+++ b/pkg/front_end/testcases/general/bug37476.dart
@@ -23,7 +23,7 @@
 
 main() {
   try {
-    a.foo /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ ();
+    a.foo /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ ();
     throw 'Expected TypeError';
   } on TypeError catch (e) {
     print(e);
diff --git a/pkg/front_end/testcases/general/bug37476.dart.strong.expect b/pkg/front_end/testcases/general/bug37476.dart.strong.expect
index 85d07b8..49098e1 100644
--- a/pkg/front_end/testcases/general/bug37476.dart.strong.expect
+++ b/pkg/front_end/testcases/general/bug37476.dart.strong.expect
@@ -24,7 +24,7 @@
 static field self::B<core::num*>* b = new self::B::•<core::int*>();
 static method main() → dynamic {
   try {
-    self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "Expected TypeError";
   }
   on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
index 85d07b8..49098e1 100644
--- a/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
@@ -24,7 +24,7 @@
 static field self::B<core::num*>* b = new self::B::•<core::int*>();
 static method main() → dynamic {
   try {
-    self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "Expected TypeError";
   }
   on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart b/pkg/front_end/testcases/general/error_locations/error_location_01.dart
new file mode 100644
index 0000000..84034a1
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_01_lib1.dart';
+import 'error_location_01_lib2.dart';
+
+main() {
+  foo();
+  bar();
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect
new file mode 100644
index 0000000..14fe62f
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → self2::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic
+  ;
+
+library;
+import self as self3;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect
new file mode 100644
index 0000000..3df9b64
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect
@@ -0,0 +1,44 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart:8:9: Error: Constant evaluation error:
+//   const Foo(0);
+//         ^
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+//
+library;
+import self as self;
+import "error_location_01_lib1.dart" as err;
+import "error_location_01_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic {
+  err::foo();
+  err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic {
+  invalid-expression "This assertion failed.";
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect
new file mode 100644
index 0000000..3df9b64
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect
@@ -0,0 +1,44 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart:8:9: Error: Constant evaluation error:
+//   const Foo(0);
+//         ^
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+//
+library;
+import self as self;
+import "error_location_01_lib1.dart" as err;
+import "error_location_01_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic {
+  err::foo();
+  err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic {
+  invalid-expression "This assertion failed.";
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+  const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+  new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart
new file mode 100644
index 0000000..e35bf9e
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_01_lib1.dart';
+
+bar() {
+  const Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart b/pkg/front_end/testcases/general/error_locations/error_location_02.dart
new file mode 100644
index 0000000..938b958
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_02_lib1.dart';
+import 'error_location_02_lib2.dart';
+import 'error_location_02_lib3.dart';
+
+main() {
+  foo();
+  print(fooField2);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect
new file mode 100644
index 0000000..25620a0
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → self2::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic
+  ;
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field self2::Foo* fooField = const self2::Foo::•(0);
+
+library;
+import self as self4;
+import "error_location_02_lib1.dart" as self2;
+import "error_location_02_lib2.dart" as self3;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field self2::Foo* fooField2 = self3::fooField;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect
new file mode 100644
index 0000000..efddc10
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect
@@ -0,0 +1,65 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:19: Error: Constant evaluation error:
+// const fooField2 = fooField;
+//                   ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = fooField;
+//       ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+//                        ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+//       ^
+//
+library;
+import self as self;
+import "error_location_02_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic {
+  err::foo();
+  core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect
new file mode 100644
index 0000000..efddc10
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect
@@ -0,0 +1,65 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:19: Error: Constant evaluation error:
+// const fooField2 = fooField;
+//                   ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = fooField;
+//       ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+//                        ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+//       ^
+//
+library;
+import self as self;
+import "error_location_02_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic {
+  err::foo();
+  core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+  const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+  new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart
new file mode 100644
index 0000000..d526e38
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_02_lib1.dart';
+
+const fooField = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart
new file mode 100644
index 0000000..7123ffc
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_02_lib2.dart';
+
+const fooField2 = fooField;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart b/pkg/front_end/testcases/general/error_locations/error_location_03.dart
new file mode 100644
index 0000000..47bffaf
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_03_lib1.dart';
+import 'error_location_03_lib2.dart';
+import 'error_location_03_lib3.dart';
+
+main() {
+  foo();
+  print(fooField);
+  print(fooField2);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect
new file mode 100644
index 0000000..e2689c9
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → self2::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic
+  ;
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field self2::Foo* fooField = const self2::Foo::•(0);
+
+library;
+import self as self4;
+import "error_location_03_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field self2::Foo* fooField2 = const self2::Foo::•(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect
new file mode 100644
index 0000000..4028b04
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect
@@ -0,0 +1,66 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+//                        ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+//       ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:25: Error: Constant evaluation error:
+// const fooField2 = const Foo(0);
+//                         ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = const Foo(0);
+//       ^
+//
+library;
+import self as self;
+import "error_location_03_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic {
+  err::foo();
+  core::print(invalid-expression "This assertion failed.");
+  core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect
new file mode 100644
index 0000000..4028b04
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect
@@ -0,0 +1,66 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+//                        ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+//       ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:25: Error: Constant evaluation error:
+// const fooField2 = const Foo(0);
+//                         ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = const Foo(0);
+//       ^
+//
+library;
+import self as self;
+import "error_location_03_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic {
+  err::foo();
+  core::print(invalid-expression "This assertion failed.");
+  core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+  const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+  new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart
new file mode 100644
index 0000000..a889a34
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_03_lib1.dart';
+
+const fooField = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart
new file mode 100644
index 0000000..09a8a3b
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_03_lib1.dart';
+
+const fooField2 = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart b/pkg/front_end/testcases/general/error_locations/error_location_04.dart
new file mode 100644
index 0000000..353cc90
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_04_lib1.dart';
+import 'error_location_04_lib2.dart';
+
+main() {
+  foo();
+  bar();
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect
new file mode 100644
index 0000000..4034b8b
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → self2::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic
+  ;
+
+library;
+import self as self3;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+  final field self2::Foo* x;
+  const constructor •() → self3::Bar*
+    : self3::Bar::x = const self2::Foo::•(0), super core::Object::•()
+    ;
+}
+static method bar() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect
new file mode 100644
index 0000000..ac754c7
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect
@@ -0,0 +1,50 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart:9:27: Error: Constant evaluation error:
+//   const Bar() : x = const Foo(0);
+//                           ^
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+//
+library;
+import self as self;
+import "error_location_04_lib1.dart" as err;
+import "error_location_04_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic {
+  err::foo();
+  err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+  final field err::Foo* x;
+  const constructor •() → err2::Bar*
+    : err2::Bar::x = invalid-expression "This assertion failed.", super core::Object::•()
+    ;
+}
+static method bar() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect
new file mode 100644
index 0000000..ac754c7
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect
@@ -0,0 +1,50 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart:9:27: Error: Constant evaluation error:
+//   const Bar() : x = const Foo(0);
+//                           ^
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart:6:31: Context: This assertion failed.
+//   const Foo(int i) : assert(i > 0);
+//                               ^
+//
+library;
+import self as self;
+import "error_location_04_lib1.dart" as err;
+import "error_location_04_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic {
+  err::foo();
+  err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  const constructor •(core::int* i) → err::Foo*
+    : assert(i.{core::num::>}(0)), super core::Object::•()
+    ;
+}
+static method foo() → dynamic {
+  new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+  final field err::Foo* x;
+  const constructor •() → err2::Bar*
+    : err2::Bar::x = invalid-expression "This assertion failed.", super core::Object::•()
+    ;
+}
+static method bar() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+  const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+  new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart
new file mode 100644
index 0000000..24de171
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_location_04_lib1.dart';
+
+class Bar {
+  final Foo x;
+  const Bar() : x = const Foo(0);
+}
+
+bar() {}
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
index 3edc43d..1e430dd 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
@@ -9,7 +9,7 @@
   ;
 static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
   ;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
   ;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
index 2323d85..4c4931a 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
@@ -40,7 +40,7 @@
   return t;
 static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
   return t;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
   return t;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
index 2323d85..4c4931a 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
@@ -40,7 +40,7 @@
   return t;
 static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
   return t;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
   return t;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/general/magic_const.dart.strong.expect b/pkg/front_end/testcases/general/magic_const.dart.strong.expect
index baa2e58..6d9ece4 100644
--- a/pkg/front_end/testcases/general/magic_const.dart.strong.expect
+++ b/pkg/front_end/testcases/general/magic_const.dart.strong.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Constant evaluation error:
+// foo({a: Constant(), b: Constant(), c: []}) {}
+//                                       ^
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Context: Can't have a non-constant List literal within a const context.
 // foo({a: Constant(), b: Constant(), c: []}) {}
 //                                       ^
 // pkg/front_end/testcases/general/magic_const.dart:15:36: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect b/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
index baa2e58..6d9ece4 100644
--- a/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Constant evaluation error:
+// foo({a: Constant(), b: Constant(), c: []}) {}
+//                                       ^
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Context: Can't have a non-constant List literal within a const context.
 // foo({a: Constant(), b: Constant(), c: []}) {}
 //                                       ^
 // pkg/front_end/testcases/general/magic_const.dart:15:36: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
index 9e85373..7998fd7 100644
--- a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
+++ b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: Constant evaluation error:
+//   C({a: 0, b: T}) : trace = "a: $a, b: $b";
+//               ^
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Context: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
 //   C({a: 0, b: T}) : trace = "a: $a, b: $b";
 //               ^
 // pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:12: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
index 91cecbd..05cc2ce 100644
--- a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: Constant evaluation error:
+//   C({a: 0, b: T}) : trace = "a: $a, b: $b";
+//               ^
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Context: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
 //   C({a: 0, b: T}) : trace = "a: $a, b: $b";
 //               ^
 // pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:12: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart b/pkg/front_end/testcases/general/non_covariant_checks.dart
index bf2dac8..679753c 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart
@@ -224,25 +224,25 @@
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>() ->* S */ field12;
+    c. /*@ checkReturn=<S extends num* = dynamic>() ->* S* */ field12;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ field13;
+    c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ field13;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* S */ field14;
+    c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* S* */ field14;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S) ->* void */ field15;
+    c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S*) ->* void */ field15;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
@@ -290,25 +290,25 @@
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>() ->* S */ getter12;
+    c. /*@ checkReturn=<S extends num* = dynamic>() ->* S* */ getter12;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ getter13;
+    c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ getter13;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* S */ getter14;
+    c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* S* */ getter14;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
   }
   try {
-    c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S) ->* void */ getter15;
+    c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S*) ->* void */ getter15;
     throw 'TypeError expected';
   } on TypeError catch (e) {
     print(e);
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
index 30be3b1..0b3bcfc 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
@@ -192,28 +192,28 @@
     core::print(e);
   }
   try {
-    c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+    c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+    c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+    c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
@@ -267,28 +267,28 @@
     core::print(e);
   }
   try {
-    c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+    c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+    c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+    c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
index 30be3b1..0b3bcfc 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
@@ -192,28 +192,28 @@
     core::print(e);
   }
   try {
-    c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+    c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+    c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+    c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
@@ -267,28 +267,28 @@
     core::print(e);
   }
   try {
-    c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+    c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+    c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+    c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
     core::print(e);
   }
   try {
-    c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+    c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
     throw "TypeError expected";
   }
   on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
index 193f75c..09d8a3c 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
@@ -2,20 +2,20 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Foo<self::Foo::T*>*
     ;
 }
 abstract class Bar extends core::Object {
   synthetic constructor •() → self::Bar*
     ;
-  abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+  abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
 }
 class Hest extends core::Object implements self::Bar {
   synthetic constructor •() → self::Hest*
     ;
   @core::override
-  method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void
+  method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void
     ;
 }
 static method main() → void
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
index b606dd1..5b088fe 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Foo<self::Foo::T*>*
     : super core::Object::•()
     ;
@@ -11,14 +11,14 @@
   synthetic constructor •() → self::Bar*
     : super core::Object::•()
     ;
-  abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+  abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
 }
 class Hest extends core::Object implements self::Bar {
   synthetic constructor •() → self::Hest*
     : super core::Object::•()
     ;
   @#C1
-  method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void {}
+  method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void {}
 }
 static method main() → void {}
 
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
index b606dd1..5b088fe 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Foo<self::Foo::T*>*
     : super core::Object::•()
     ;
@@ -11,14 +11,14 @@
   synthetic constructor •() → self::Bar*
     : super core::Object::•()
     ;
-  abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+  abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
 }
 class Hest extends core::Object implements self::Bar {
   synthetic constructor •() → self::Hest*
     : super core::Object::•()
     ;
   @#C1
-  method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void {}
+  method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void {}
 }
 static method main() → void {}
 
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart b/pkg/front_end/testcases/general/override_setter_with_field.dart
new file mode 100644
index 0000000..687d9a5
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class A {
+  void set x(Object y);
+}
+
+class B implements A {
+  int x;
+}
+
+main() {
+  new B().x = 5;
+}
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect b/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect
new file mode 100644
index 0000000..f54d02a
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect
@@ -0,0 +1,27 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/override_setter_with_field.dart:10:7: Error: The field 'B.x' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'A.x'.
+//  - 'Object' is from 'dart:core'.
+//   int x;
+//       ^
+// pkg/front_end/testcases/general/override_setter_with_field.dart:6:12: Context: This is the overridden method ('x').
+//   void set x(Object y);
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  abstract set x(core::Object* y) → void;
+}
+class B extends core::Object implements self::A {
+  field core::int* x;
+  synthetic constructor •() → self::B*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect b/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect
new file mode 100644
index 0000000..58904b1
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect
@@ -0,0 +1,30 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/override_setter_with_field.dart:10:7: Error: The field 'B.x' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'A.x'.
+//  - 'Object' is from 'dart:core'.
+//   int x;
+//       ^
+// pkg/front_end/testcases/general/override_setter_with_field.dart:6:12: Context: This is the overridden method ('x').
+//   void set x(Object y);
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  abstract set x(core::Object* y) → void;
+}
+class B extends core::Object implements self::A {
+  field core::int* x = null;
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::B::•().{self::B::x} = 5;
+}
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
index 2160bc2..fa3f49e 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
@@ -9,7 +9,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
index 8da8025..f5eae0d 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
@@ -9,7 +9,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
index 8da8025..f5eae0d 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
@@ -9,7 +9,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
index d4ea589..7251f88 100644
--- a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
+++ b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
@@ -34,7 +34,7 @@
 }
 static method f<S extends core::Object* = dynamic>(self::f::S* s) → core::List<self::f::S*>* {
   if(s is self::A*) {
-    core::List<self::f::S* extends self::A*>* list = self::g<self::f::S* extends self::A*>(s{self::f::S* extends self::A*});
+    core::List<self::f::S* & self::A* /* '*' & '*' = '*' */>* list = self::g<self::f::S* & self::A* /* '*' & '*' = '*' */>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
     return list;
   }
   return null;
diff --git a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
index d4ea589..7251f88 100644
--- a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
@@ -34,7 +34,7 @@
 }
 static method f<S extends core::Object* = dynamic>(self::f::S* s) → core::List<self::f::S*>* {
   if(s is self::A*) {
-    core::List<self::f::S* extends self::A*>* list = self::g<self::f::S* extends self::A*>(s{self::f::S* extends self::A*});
+    core::List<self::f::S* & self::A* /* '*' & '*' = '*' */>* list = self::g<self::f::S* & self::A* /* '*' & '*' = '*' */>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
     return list;
   }
   return null;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml
new file mode 100644
index 0000000..0ecda031
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml
@@ -0,0 +1,93 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a two new files each with usage of it. An error should occur each place.
+# Fix one and the error should still occur in the other.
+# Fix the other but re-introduce the first and the error should still occur.
+# Fix both and the error should go away.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+      lib.dart: |
+        class Foo {
+          const Foo(int i) : assert(i > 0);
+        }
+        foo() {
+          new Foo(0);
+        }
+    expectedLibraryCount: 2
+    errors: false
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        import 'lib2.dart';
+        import 'lib3.dart';
+        main() {
+          foo();
+          print(fooField2);
+        }
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(0);
+      lib3.dart: |
+        import 'lib.dart';
+        const fooField2 = const Foo(0);
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - lib2.dart
+    sources:
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(1);
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - lib2.dart
+      - lib3.dart
+    sources:
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(0);
+      lib3.dart: |
+        import 'lib.dart';
+        const fooField2 = const Foo(1);
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - lib2.dart
+      - lib3.dart
+    sources:
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(1);
+      lib3.dart: |
+        import 'lib.dart';
+        const fooField2 = const Foo(1);
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml
new file mode 100644
index 0000000..4c8455b
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml
@@ -0,0 +1,65 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add another const class that references it. Error.
+# Fixing that should fix everything.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+      lib.dart: |
+        class Foo {
+          const Foo(int i) : assert(i > 0);
+        }
+        foo() {
+          new Foo(0);
+        }
+    expectedLibraryCount: 2
+    errors: false
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        import 'lib2.dart';
+        main() {
+          foo();
+          bar();
+        }
+      lib2.dart: |
+        import 'lib.dart';
+        class Bar {
+          final Foo x;
+          const Bar() : x = const Foo(0);
+        }
+        bar() {}
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - lib2.dart
+    sources:
+      lib2.dart: |
+        import 'lib.dart';
+        class Bar {
+          final Foo x;
+          const Bar() : x = const Foo(1);
+        }
+        bar() {}
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml
new file mode 100644
index 0000000..79727eb
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml
@@ -0,0 +1,49 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with errors in it, then - without fixing the errors -
+# recompile. Make sure we still get errors. As long as we don't fix the error,
+# we keep getting errors. Once we fix it, we no longer get errors.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        class Foo<X extends Bar> {}
+      lib.dart: |
+        // The error is here: Foo is unknown
+        // (although it might give some other error instead)
+        class Bar<X extends Foo<Null>> {}
+    expectedLibraryCount: 2
+    errors: true
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        class Foo {}
+    expectInitializeFromDill: false
+    expectedLibraryCount: 2
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - main.dart
+      - lib.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        class Foo<X extends Bar> {}
+      lib.dart: |
+        import 'main.dart';
+        class Bar<X extends Foo<Null>> {}
+    expectInitializeFromDill: false
+    expectedLibraryCount: 2
+ 
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml
new file mode 100644
index 0000000..1b18f5c
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml
@@ -0,0 +1,79 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with errors in it, then - without fixing the errors -
+# recompile. Make sure we still get errors. As long as we don't fix the error,
+# we keep getting errors. Once we fix it, we no longer get errors.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+      lib.dart: |
+        import 'nonexisting.dart';
+        foo() {}
+    expectedLibraryCount: 2
+    errors: true
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+          foo();
+        }
+    expectInitializeFromDill: false
+    expectedLibraryCount: 2
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        import 'lib2.dart';
+        main() {
+          foo();
+          bar();
+        }
+      lib2.dart: |
+        bar() {
+          print("hello");
+        }
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - lib2.dart
+    sources:
+      lib2.dart: |
+        bar() {
+          print("hello2");
+        }
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
+
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - lib.dart
+    sources:
+      lib.dart: |
+        foo() {}
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml
new file mode 100644
index 0000000..9e1b824
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml
@@ -0,0 +1,60 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a new file with usage of it. An error should occur.
+# Remove said file again and the error should go away.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+      lib.dart: |
+        class Foo {
+          const Foo(int i) : assert(i > 0);
+        }
+        foo() {
+          new Foo(0);
+        }
+    expectedLibraryCount: 2
+    errors: false
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        import 'lib2.dart';
+        main() {
+          foo();
+        }
+      lib2.dart: |
+        import 'lib.dart';
+        bar() {
+          const Foo(0);
+        }
+    expectInitializeFromDill: false
+    expectedLibraryCount: 3
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+    expectInitializeFromDill: false
+    expectedLibraryCount: 2
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml
new file mode 100644
index 0000000..c8ec3fa
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml
@@ -0,0 +1,62 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a new file with usage of it. An error should occur.
+# Fix said file again and the error should go away.
+# Any references to the constant shouldn't matter in this regard.
+
+type: newworld
+strong: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        main() {
+          foo();
+        }
+      lib.dart: |
+        class Foo {
+          const Foo(int i) : assert(i > 0);
+        }
+        foo() {
+          new Foo(0);
+        }
+    expectedLibraryCount: 2
+    errors: false
+  - entry: main.dart
+    errors: true
+    worldType: updated
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'lib.dart';
+        import 'lib2.dart';
+        import 'lib3.dart';
+        main() {
+          foo();
+          print(fooField2);
+        }
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(0);
+      lib3.dart: |
+        import 'lib2.dart';
+        const fooField2 = fooField;
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
+  - entry: main.dart
+    errors: false
+    worldType: updated
+    invalidate:
+      - lib2.dart
+    sources:
+      lib2.dart: |
+        import 'lib.dart';
+        const fooField = const Foo(1);
+    expectInitializeFromDill: false
+    expectedLibraryCount: 4
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
index f3d01d2..3cae5cc 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
@@ -2,4 +2,4 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE.md file.
 
-# Status file for the test suite ../test/incremental_load_from_dill_yaml_test.dart.
+# Status file for the test suite ../test/incremental_load_from_dill_test.dart.
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
index 4d266f4..408d7df 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
@@ -6,7 +6,7 @@
   synthetic constructor •() → self::Cloneable<self::Cloneable::T*>*
     ;
 }
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
   generic-covariant-impl field self::Pair::T* t;
   generic-covariant-impl field self::Pair::U* u;
   constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
index 2359c4d..c7e9952 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
@@ -28,7 +28,7 @@
     : super core::Object::•()
     ;
 }
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
   generic-covariant-impl field self::Pair::T* t;
   generic-covariant-impl field self::Pair::U* u;
   constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
index 2359c4d..c7e9952 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
@@ -28,7 +28,7 @@
     : super core::Object::•()
     ;
 }
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
   generic-covariant-impl field self::Pair::T* t;
   generic-covariant-impl field self::Pair::U* u;
   constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
index cc6f9e2..d7f5411 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
@@ -10,6 +10,6 @@
     return (self::C::T* y) → core::Null* {};
 }
 static method test(self::C<core::String*>* c) → void {
-  (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U) →* (core::String*) →* void<core::int*>;
+  (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U*) →* (core::String*) →* void<core::int*>;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
index cc6f9e2..d7f5411 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
@@ -10,6 +10,6 @@
     return (self::C::T* y) → core::Null* {};
 }
 static method test(self::C<core::String*>* c) → void {
-  (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U) →* (core::String*) →* void<core::int*>;
+  (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U*) →* (core::String*) →* void<core::int*>;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
index f952fac..e769695 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
@@ -18,7 +18,7 @@
   synthetic constructor •() → self::I<self::I::X*>*
     ;
 }
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
   synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
     ;
 }
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
index e8afc30..e44fcb9 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
@@ -19,7 +19,7 @@
     : super core::Object::•()
     ;
 }
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
   synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
     : super self::I::•()
     ;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
index 5ca76b8..d17f94c 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
@@ -19,7 +19,7 @@
     : super core::Object::•()
     ;
 }
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
   synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
     : super self::I::•()
     ;
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart b/pkg/front_end/testcases/inference/promote_bounds.dart
index 37cc023..7a631cb 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart
@@ -20,7 +20,7 @@
   }
   if (a is C) {
     // Promoted; we can now call bar.
-    /*@ promotedType=f::T* extends C* */ a. /*@target=C::bar*/ bar();
+    /*@ promotedType=f::T* & C* */ a. /*@target=C::bar*/ bar();
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
index a10d272..3e0e207 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
@@ -19,7 +19,7 @@
     a.{self::B::foo}();
   }
   if(a is self::C*) {
-    a{self::f::T* extends self::C*}.{self::C::bar}();
+    a{self::f::T* & self::C* /* '*' & '*' = '*' */}.{self::C::bar}();
   }
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
index a10d272..3e0e207 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
@@ -19,7 +19,7 @@
     a.{self::B::foo}();
   }
   if(a is self::C*) {
-    a{self::f::T* extends self::C*}.{self::C::bar}();
+    a{self::f::T* & self::C* /* '*' & '*' = '*' */}.{self::C::bar}();
   }
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
index b3d2329..814e963 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
@@ -10,7 +10,7 @@
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
index 9f78ee2..6202c0e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
@@ -12,11 +12,11 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
     : super core::Object::•()
     ;
 }
 static method main() → dynamic {
-  self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null*) →* self::B<dynamic, dynamic>*, core::num*>* d;
+  self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null?) →* self::B<dynamic, dynamic>*, core::num*>* d;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
index 9f78ee2..6202c0e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
@@ -12,11 +12,11 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
     : super core::Object::•()
     ;
 }
 static method main() → dynamic {
-  self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null*) →* self::B<dynamic, dynamic>*, core::num*>* d;
+  self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null?) →* self::B<dynamic, dynamic>*, core::num*>* d;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
index b719a1c..bef6eb8 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
index 093fa07c..77bf163 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
index 093fa07c..77bf163 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
index 9038ebd..dcce18a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
 class C extends core::Object {
   synthetic constructor •() → self::C*
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
index a04653f..0ce72d7 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
 class C extends core::Object {
   synthetic constructor •() → self::C*
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
index a04653f..0ce72d7 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
 class C extends core::Object {
   synthetic constructor •() → self::C*
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
index 941b9b6..38562f5 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
@@ -2,10 +2,10 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
index 61e4ec3..6389a65 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
@@ -2,10 +2,10 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
index 61e4ec3..6389a65 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
@@ -2,10 +2,10 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
index 28f1f4b..60fb2e3 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc;
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc;
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc;
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
index 72e6fc0..592f642 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc = <self::C<core::num*, (core::Null*) →* void>*>[];
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc = <self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>{};
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc = <self::C<core::num*, (core::Null?) →* void>*>[];
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc = <self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
index 72e6fc0..592f642 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
@@ -2,11 +2,11 @@
 import self as self;
 import "dart:core" as core;
 
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc = <self::C<core::num*, (core::Null*) →* void>*>[];
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc = <self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>{};
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc = <self::C<core::num*, (core::Null?) →* void>*>[];
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc = <self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
index 543c453..b99b029 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
@@ -2,15 +2,15 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     ;
 }
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
index 0867d26..cf5841c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
@@ -2,16 +2,16 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
index 0867d26..cf5841c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
@@ -2,16 +2,16 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
index bcf89d2..41e06b4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
@@ -2,17 +2,17 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     ;
 }
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld;
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md;
-static field core::List<self::E<(core::Null*) →* void>*>* le;
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me;
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld;
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md;
+static field core::List<self::E<(core::Null?) →* void>*>* le;
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
index 47b5906..b87ae59 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
@@ -2,18 +2,18 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>[];
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>{};
-static field core::List<self::E<(core::Null*) →* void>*>* le = <self::E<(core::Null*) →* void>*>[];
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me = <self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>{};
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>[];
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>{};
+static field core::List<self::E<(core::Null?) →* void>*>* le = <self::E<(core::Null?) →* void>*>[];
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me = <self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
index 47b5906..b87ae59 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -2,18 +2,18 @@
 import self as self;
 import "dart:core" as core;
 
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>[];
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>{};
-static field core::List<self::E<(core::Null*) →* void>*>* le = <self::E<(core::Null*) →* void>*>[];
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me = <self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>{};
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>[];
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>{};
+static field core::List<self::E<(core::Null?) →* void>*>* le = <self::E<(core::Null?) →* void>*>[];
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me = <self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
index ab32947..ac077fd 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
@@ -10,15 +10,15 @@
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
index 9dfe27e..30e09b1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
@@ -12,17 +12,17 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     : super core::Object::•()
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
index 9dfe27e..30e09b1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
@@ -12,17 +12,17 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     : super core::Object::•()
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
index e9f5ac1..259a0da 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
@@ -10,15 +10,15 @@
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
index 8818c9d4..f5ddef9 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
@@ -12,17 +12,17 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     : super core::Object::•()
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
index 8818c9d4..f5ddef9 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -12,17 +12,17 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
     : super core::Object::•()
     ;
 }
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
   synthetic constructor •() → self::F<self::F::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
index e767b17..87dce27 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
@@ -6,15 +6,15 @@
   synthetic constructor •() → self::A<self::A::X*>*
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
index 6159d34..96c2e9a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
index 6159d34..96c2e9a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
index 04e5fdf..0eaaf49 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
@@ -6,17 +6,17 @@
   synthetic constructor •() → self::A<self::A::X*>*
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc;
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc;
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld;
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md;
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc;
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc;
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld;
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
index 99233e6..1483925 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
@@ -7,18 +7,18 @@
     : super core::Object::•()
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc = <self::C<dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc = <self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld = <self::D<core::num*, (core::Null*) →* core::num*>*>[];
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md = <self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>{};
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc = <self::C<dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc = <self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld = <self::D<core::num*, (core::Null?) →* core::num*>*>[];
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md = <self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
index 99233e6..1483925 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
@@ -7,18 +7,18 @@
     : super core::Object::•()
     ;
 }
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     : super core::Object::•()
     ;
 }
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc = <self::C<dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc = <self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld = <self::D<core::num*, (core::Null*) →* core::num*>*>[];
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md = <self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>{};
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc = <self::C<dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc = <self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld = <self::D<core::num*, (core::Null?) →* core::num*>*>[];
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md = <self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
index 4b449c4..6a0bd29 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::B<self::B::T*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
index d1590e7..feb336e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
@@ -14,7 +14,7 @@
 import self as self;
 import "dart:core" as core;
 
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::B<self::B::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
index d1590e7..feb336e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
 import self as self;
 import "dart:core" as core;
 
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::B<self::B::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
index 556a2ee..a1afe46 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
@@ -7,21 +7,6 @@
 // class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
 //         ^
 //
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-//                      ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                            ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                                         ^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -37,32 +22,32 @@
   synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
     ;
 }
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     ;
 }
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
     ;
 }
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
     ;
 }
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
     ;
 }
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
     ;
 }
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
-  synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+  synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
     ;
 }
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
-  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
     ;
 }
 static field self::D<self::A<dynamic>*, self::A<dynamic>*>* d;
@@ -70,7 +55,7 @@
 static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
 static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
 static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
index cc78f70..f195645 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
@@ -7,21 +7,6 @@
 // class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
 //         ^
 //
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-//                      ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                            ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                                         ^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -40,38 +25,38 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
     : super core::Object::•()
     ;
 }
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
     : super core::Object::•()
     ;
 }
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
     : super core::Object::•()
     ;
 }
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
     : super core::Object::•()
     ;
 }
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
-  synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+  synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
     : super core::Object::•()
     ;
 }
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
-  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
     : super core::Object::•()
     ;
 }
@@ -80,6 +65,6 @@
 static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
 static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
 static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
index cc78f70..f195645 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
@@ -7,21 +7,6 @@
 // class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
 //         ^
 //
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-//                      ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                            ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-//     X extends Function(V), Y extends Z, Z extends T> {}
-//                                         ^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -40,38 +25,38 @@
     : super core::Object::•()
     ;
 }
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
     : super core::Object::•()
     ;
 }
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
   synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
     : super core::Object::•()
     ;
 }
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
     : super core::Object::•()
     ;
 }
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
   synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
     : super core::Object::•()
     ;
 }
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
     : super core::Object::•()
     ;
 }
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
-  synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+  synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
     : super core::Object::•()
     ;
 }
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
-  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+  synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
     : super core::Object::•()
     ;
 }
@@ -80,6 +65,6 @@
 static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
 static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
 static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
index 78b6d1c..e4d29b4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
@@ -6,50 +6,50 @@
   synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     ;
 }
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
index ecb02f3..c56a66f 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
@@ -7,58 +7,58 @@
     : super core::Object::•()
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     : super core::Object::•()
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     : super core::Object::•()
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     : super core::Object::•()
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     : super core::Object::•()
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     : super core::Object::•()
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     : super core::Object::•()
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     : super core::Object::•()
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
index ecb02f3..c56a66f 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
@@ -7,58 +7,58 @@
     : super core::Object::•()
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     : super core::Object::•()
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     : super core::Object::•()
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     : super core::Object::•()
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     : super core::Object::•()
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     : super core::Object::•()
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     : super core::Object::•()
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     : super core::Object::•()
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
index 0db7d67..c60f956 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
@@ -6,59 +6,59 @@
   synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     ;
 }
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1;
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1;
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2;
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2;
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3;
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3;
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4;
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4;
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1;
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1;
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2;
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2;
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3;
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3;
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4;
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4;
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le;
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me;
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1;
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1;
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2;
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2;
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3;
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3;
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4;
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4;
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1;
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1;
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2;
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2;
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3;
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3;
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4;
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4;
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le;
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
index f7a9579..fad1c97 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
@@ -7,67 +7,67 @@
     : super core::Object::•()
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     : super core::Object::•()
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     : super core::Object::•()
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     : super core::Object::•()
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     : super core::Object::•()
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     : super core::Object::•()
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     : super core::Object::•()
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     : super core::Object::•()
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le = <self::E<(core::Null*) →* dynamic>*>[];
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me = <self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>{};
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le = <self::E<(core::Null?) →* dynamic>*>[];
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me = <self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
index f7a9579..fad1c97 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -7,67 +7,67 @@
     : super core::Object::•()
     ;
 }
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
     : super core::Object::•()
     ;
 }
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
     : super core::Object::•()
     ;
 }
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
     : super core::Object::•()
     ;
 }
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
     : super core::Object::•()
     ;
 }
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
     : super core::Object::•()
     ;
 }
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
     : super core::Object::•()
     ;
 }
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
     : super core::Object::•()
     ;
 }
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
     : super core::Object::•()
     ;
 }
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
   synthetic constructor •() → self::E<self::E::X*>*
     : super core::Object::•()
     ;
 }
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le = <self::E<(core::Null*) →* dynamic>*>[];
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me = <self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>{};
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le = <self::E<(core::Null?) →* dynamic>*>[];
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me = <self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>{};
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
index 09fd8ad..c3b608e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
@@ -21,7 +21,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
index 10af610..ab85dcf 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
@@ -21,7 +21,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
index 10af610..ab85dcf 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
@@ -21,7 +21,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
index b4a29e8..450c215 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
@@ -9,11 +9,11 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
index 4983685..8f79b89 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
@@ -9,12 +9,12 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
index 4983685..8f79b89 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
@@ -9,12 +9,12 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
index cda7cca..b131c3a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
@@ -21,11 +21,11 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
index 2e957c6..ec10848 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
@@ -21,12 +21,12 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
index 2e957c6..ec10848 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
@@ -21,12 +21,12 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
index 2337453..7b8d8f1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
index 2950575..87f748c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
index 2950575..87f748c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
index bd2bd0e..1dfb185 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
index 5a73de7..37c1f7b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
index 5a73de7..37c1f7b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
index 2097fc5..4c04e3b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
index 6c8df32..3bf035e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
index 6c8df32..3bf035e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
 import self as self;
 import "dart:core" as core;
 
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
index 040e2a3..4b818fd 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::X*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
index 2682021..bccb0a0 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
index 2682021..bccb0a0 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::X*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
index 2075628..6a8424b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
index 35d7d8a..e533635 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
index 35d7d8a..e533635 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
   synthetic constructor •() → self::A<self::A::T*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
index 7fd0a96..bbce9e4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
 static field ((dynamic) →* dynamic) →* dynamic b;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
index 9bc70a4..d59e608 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
@@ -3,6 +3,6 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
 static field ((dynamic) →* dynamic) →* dynamic b;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
index 9bc70a4..d59e608 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
@@ -3,6 +3,6 @@
 import "dart:core" as core;
 
 typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
 static field ((dynamic) →* dynamic) →* dynamic b;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/late.dart.outline.expect b/pkg/front_end/testcases/nnbd/late.dart.outline.expect
index 3ab3586..4c3658f 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.outline.expect
@@ -3,16 +3,16 @@
 import "dart:core" as core;
 
 class Class extends core::Object {
-  late field core::int* lateInstanceField;
-  late final field core::int* finalLateInstanceField;
-  late static field core::int* lateStaticField;
-  late static final field core::int* finalLateStaticField;
+  late field core::int lateInstanceField;
+  late final field core::int finalLateInstanceField;
+  late static field core::int lateStaticField;
+  late static final field core::int finalLateStaticField;
   synthetic constructor •() → self::Class*
     ;
   method method() → dynamic
     ;
 }
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
index 2315067..06376e9 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
@@ -3,18 +3,18 @@
 import "dart:core" as core;
 
 class Class extends core::Object {
-  late field core::int* lateInstanceField = null;
-  late final field core::int* finalLateInstanceField = 0;
-  late static field core::int* lateStaticField = null;
-  late static final field core::int* finalLateStaticField = 0;
+  late field core::int lateInstanceField = null;
+  late final field core::int finalLateInstanceField = 0;
+  late static field core::int lateStaticField = null;
+  late static final field core::int finalLateStaticField = 0;
   synthetic constructor •() → self::Class*
     : super core::Object::•()
     ;
   method method() → dynamic {
-    late core::int* lateVariable;
-    late final core::int* lateFinalVariable = 0;
+    late core::int lateVariable;
+    late final core::int lateFinalVariable = 0;
   }
 }
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
index 2315067..06376e9 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
@@ -3,18 +3,18 @@
 import "dart:core" as core;
 
 class Class extends core::Object {
-  late field core::int* lateInstanceField = null;
-  late final field core::int* finalLateInstanceField = 0;
-  late static field core::int* lateStaticField = null;
-  late static final field core::int* finalLateStaticField = 0;
+  late field core::int lateInstanceField = null;
+  late final field core::int finalLateInstanceField = 0;
+  late static field core::int lateStaticField = null;
+  late static final field core::int finalLateStaticField = 0;
   synthetic constructor •() → self::Class*
     : super core::Object::•()
     ;
   method method() → dynamic {
-    late core::int* lateVariable;
-    late final core::int* lateFinalVariable = 0;
+    late core::int lateVariable;
+    late final core::int lateFinalVariable = 0;
   }
 }
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
index 0a3ac11..18fe203 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
@@ -20,12 +20,12 @@
 import "dart:core" as core;
 
 class Foo extends core::Object {
-  field core::int* field;
+  field core::int? field;
   synthetic constructor •() → self::Foo*
     ;
-  abstract method bar(core::int* x) → core::int*;
+  abstract method bar(core::int? x) → core::int?;
 }
 static method main() → dynamic
   ;
-static method test_nullable_function_type_formal_param({() →* core::int* f}) → core::int*
+static method test_nullable_function_type_formal_param({() →* core::int f}) → core::int
   ;
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
index f6ff7b9..977546a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
@@ -20,20 +20,20 @@
 import "dart:core" as core;
 
 class Foo extends core::Object {
-  field core::int* field = null;
+  field core::int? field = null;
   synthetic constructor •() → self::Foo*
     : super core::Object::•()
     ;
-  abstract method bar(core::int* x) → core::int*;
+  abstract method bar(core::int? x) → core::int?;
 }
 static method main() → dynamic {
-  self::Foo* foo = new self::Foo::•();
+  self::Foo foo = new self::Foo::•();
   foo.{self::Foo::field} = 5;
   foo.{self::Foo::bar}(6);
   self::test_nullable_function_type_formal_param(f: () → core::int* => 2);
 }
-static method test_nullable_function_type_formal_param({() →* core::int* f = #C1}) → core::int* {
-  return let final core::int* #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
+static method test_nullable_function_type_formal_param({() →* core::int f = #C1}) → core::int {
+  return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
index f6ff7b9..977546a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
@@ -20,20 +20,20 @@
 import "dart:core" as core;
 
 class Foo extends core::Object {
-  field core::int* field = null;
+  field core::int? field = null;
   synthetic constructor •() → self::Foo*
     : super core::Object::•()
     ;
-  abstract method bar(core::int* x) → core::int*;
+  abstract method bar(core::int? x) → core::int?;
 }
 static method main() → dynamic {
-  self::Foo* foo = new self::Foo::•();
+  self::Foo foo = new self::Foo::•();
   foo.{self::Foo::field} = 5;
   foo.{self::Foo::bar}(6);
   self::test_nullable_function_type_formal_param(f: () → core::int* => 2);
 }
-static method test_nullable_function_type_formal_param({() →* core::int* f = #C1}) → core::int* {
-  return let final core::int* #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
+static method test_nullable_function_type_formal_param({() →* core::int f = #C1}) → core::int {
+  return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/required.dart.outline.expect b/pkg/front_end/testcases/nnbd/required.dart.outline.expect
index 97154f2..044b885 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.outline.expect
@@ -2,16 +2,16 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
 class Class extends core::Object {
   synthetic constructor •() → self::Class*
     ;
-  method method({core::int* a, required core::int* b, required final core::int* c, required covariant final core::int* d}) → dynamic
+  method method({core::int a, required core::int b, required final core::int c, required covariant final core::int d}) → dynamic
     ;
 }
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a, required core::int* b, required final core::int* c}) → dynamic
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a, required core::int b, required final core::int c}) → dynamic
   ;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
index 7ba4cd1..a23a59d 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
@@ -2,16 +2,16 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
 class Class extends core::Object {
   synthetic constructor •() → self::Class*
     : super core::Object::•()
     ;
-  method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1, required covariant final core::int* d = #C1}) → dynamic {}
+  method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1, required covariant final core::int d = #C1}) → dynamic {}
 }
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1}) → dynamic {}
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
index 7ba4cd1..a23a59d 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
@@ -2,16 +2,16 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
 class Class extends core::Object {
   synthetic constructor •() → self::Class*
     : super core::Object::•()
     ;
-  method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1, required covariant final core::int* d = #C1}) → dynamic {}
+  method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1, required covariant final core::int d = #C1}) → dynamic {}
 }
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1}) → dynamic {}
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill b/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill
new file mode 100644
index 0000000..aff0e19
--- /dev/null
+++ b/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill
Binary files differ
diff --git a/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill b/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill
new file mode 100644
index 0000000..d38cb21
--- /dev/null
+++ b/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill
Binary files differ
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 4037f63..38b00e3 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -13,6 +13,7 @@
 general/override_check_after_inference: TypeCheckError
 general/override_check_basic: TypeCheckError
 general/override_check_with_covariant_modifier: TypeCheckError
+general/override_setter_with_field: TypeCheckError
 
 inference/conflicting_fields: TypeCheckError
 inference/conflicts_can_happen2: Fail
diff --git a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
index 8fc1e32..391c477 100644
--- a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Constant evaluation error:
+// main(arguments = [x]) {
+//                  ^
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Context: Can't have a non-constant List literal within a const context.
 // main(arguments = [x]) {
 //                  ^
 // pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:6: Context: While analyzing:
diff --git a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
index 8fc1e32..391c477 100644
--- a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
 //
 // Problems in component:
 //
-// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Constant evaluation error:
+// main(arguments = [x]) {
+//                  ^
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Context: Can't have a non-constant List literal within a const context.
 // main(arguments = [x]) {
 //                  ^
 // pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:6: Context: While analyzing:
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
index d54f1ce..6e2c9f6 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
 class A extends core::Object {
-  field <T extends core::Object* = dynamic>(T) →* core::int* f;
+  field <T extends core::Object* = dynamic>(T*) →* core::int* f;
   synthetic constructor •() → self::A*
     ;
   method test() → void
@@ -12,7 +12,7 @@
 }
 static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
   ;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
   ;
 static method test1() → void
   ;
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
index f47c10a..604c9c1 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
 class A extends core::Object {
-  field <T extends core::Object* = dynamic>(T) →* core::int* f = null;
+  field <T extends core::Object* = dynamic>(T*) →* core::int* f = null;
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
   return 3;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
   return #C1;
 static method test1() → void {
   self::bar().call<core::String*>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
index f47c10a..604c9c1 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
 
 typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
 class A extends core::Object {
-  field <T extends core::Object* = dynamic>(T) →* core::int* f = null;
+  field <T extends core::Object* = dynamic>(T*) →* core::int* f = null;
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
@@ -14,7 +14,7 @@
 }
 static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
   return 3;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
   return #C1;
 static method test1() → void {
   self::bar().call<core::String*>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
index 8187fe8..bff625e 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
@@ -3,6 +3,6 @@
 import "dart:core" as core;
 
 typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
index f1a3bea..c685791 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
@@ -3,5 +3,5 @@
 import "dart:core" as core;
 
 typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
index f1a3bea..c685791 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
@@ -3,5 +3,5 @@
 import "dart:core" as core;
 
 typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
index 64d7ec6..52693de 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
 static method producer<K extends core::Object* = dynamic>() → dynamic
   ;
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
index b01d4ea..cc1d463 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
 static method producer<K extends core::Object* = dynamic>() → dynamic {
   return <A extends core::Object* = dynamic>(core::int* v1) → <B extends core::Object* = dynamic>(A*, self::producer::K*, B*) →* core::int* {
     return <B extends core::Object* = dynamic>(A* v2, self::producer::K* v3, B* v4) → core::int* => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A, core::String*, B) →* core::int*);
+  assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, core::String*, B*) →* core::int*);
 }
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
index b01d4ea..cc1d463 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
@@ -3,12 +3,12 @@
 import "dart:core" as core;
 
 typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
 static method producer<K extends core::Object* = dynamic>() → dynamic {
   return <A extends core::Object* = dynamic>(core::int* v1) → <B extends core::Object* = dynamic>(A*, self::producer::K*, B*) →* core::int* {
     return <B extends core::Object* = dynamic>(A* v2, self::producer::K* v3, B* v4) → core::int* => 0;
   };
 }
 static method main() → dynamic {
-  assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A, core::String*, B) →* core::int*);
+  assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, core::String*, B*) →* core::int*);
 }
diff --git a/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
index f501b52..a9152eb 100644
--- a/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
@@ -6,10 +6,10 @@
   core::print((#C1) is () →* dynamic);
   core::print((<T extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
   core::print((<T extends core::num* = core::num*>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::Comparable<T>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::Comparable<S>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends (T) →* dynamic = (core::Null*) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::List<core::List<T>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::Comparable<T*>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::Comparable<S*>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends (T*) →* dynamic = (core::Null?) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::List<core::List<T*>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
index f501b52..a9152eb 100644
--- a/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
@@ -6,10 +6,10 @@
   core::print((#C1) is () →* dynamic);
   core::print((<T extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
   core::print((<T extends core::num* = core::num*>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::Comparable<T>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::Comparable<S>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends (T) →* dynamic = (core::Null*) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
-  core::print((<T extends core::List<core::List<T>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::Comparable<T*>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::Comparable<S*>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends (T*) →* dynamic = (core::Null?) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+  core::print((<T extends core::List<core::List<T*>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
index 4aaa576..45e4a38 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
@@ -2,9 +2,8 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The return type of the method 'M.y' is 'int', which does not match the return type, 'Object', of the overridden method, 'I.y'.
+// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The field 'M.y' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'I.y'.
 //  - 'Object' is from 'dart:core'.
-// Change to a subtype of 'Object'.
 //   int y;
 //       ^
 // pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:43:12: Context: This is the overridden method ('y').
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
index 2d7f586..2d52e9b 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
@@ -2,9 +2,8 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The return type of the method 'M.y' is 'int', which does not match the return type, 'Object', of the overridden method, 'I.y'.
+// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The field 'M.y' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'I.y'.
 //  - 'Object' is from 'dart:core'.
-// Change to a subtype of 'Object'.
 //   int y;
 //       ^
 // pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:43:12: Context: This is the overridden method ('y').
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 3cd71a8..df68cb5 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -6,7 +6,9 @@
 # Kernel ASTs directly, that is, code in pkg/fasta/lib/src/kernel/ with
 # strong-mode enabled.
 
-extensions/extension_methods: RuntimeError
+extensions/instance_access_of_static: RuntimeError
+extensions/invalid_explicit_access: RuntimeError
+extensions/static_access_of_instance: RuntimeError
 general/abstract_members: TypeCheckError
 general/accessors: RuntimeError
 general/ambiguous_exports: RuntimeError # Expected, this file exports two main methods.
@@ -23,6 +25,9 @@
 general/duplicated_declarations: TypeCheckError
 general/duplicated_field_initializer: RuntimeError
 general/dynamic_and_void: InstrumentationMismatch # Test assumes Dart 1.0 semantics
+general/error_locations/error_location_01: RuntimeError
+general/error_locations/error_location_02: RuntimeError
+general/error_locations/error_location_03: RuntimeError
 general/expressions: RuntimeError
 general/external_import: RuntimeError # The native extension to import doesn't exist. This is ok.
 general/fallthrough: ExpectationFileMismatch
@@ -44,6 +49,7 @@
 general/override_check_after_inference: TypeCheckError # Issue #31620
 general/override_check_basic: TypeCheckError # Issue #31620
 general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
+general/override_setter_with_field: TypeCheckError
 general/reject_generic_function_types_in_bounds: RuntimeError # Expected
 general/spread_collection: RuntimeError
 general/statements: Crash
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 3a7d406..35ef84e 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,16 +8,34 @@
 
 expression/eval: TextSerializationFailure # Was: Pass
 expression/main: TextSerializationFailure # Was: Pass
-extensions/explicit_this: TextSerializationFailure
-extensions/extension_methods: TextSerializationFailure
-extensions/implicit_this: TextSerializationFailure
 extensions/direct_instance_access: TextSerializationFailure
 extensions/direct_static_access: TextSerializationFailure
+extensions/explicit_extension_access: TextSerializationFailure
+extensions/explicit_extension_inference: TextSerializationFailure
+extensions/explicit_generic_extension_access: TextSerializationFailure
+extensions/explicit_this: TextSerializationFailure
+extensions/extension_methods: TextSerializationFailure
+extensions/implicit_extension_inference: TextSerializationFailure
+extensions/implicit_this: TextSerializationFailure
+extensions/index: TextSerializationFailure
+extensions/instance_access: TextSerializationFailure
+extensions/instance_access_of_static: TextSerializationFailure
 extensions/instance_members: TextSerializationFailure
+extensions/instance_tearoff: TextSerializationFailure
+extensions/invalid_explicit_access: TextSerializationFailure
+extensions/nested_on_types: TextSerializationFailure
+extensions/on_type_inference: TextSerializationFailure
+extensions/on_type_variable_inference: TextSerializationFailure
+extensions/operators: TextSerializationFailure
 extensions/other_kinds: TextSerializationFailure
 extensions/static_access: TextSerializationFailure
+extensions/static_access_of_instance: TextSerializationFailure
 extensions/type_variables: TextSerializationFailure
 extensions/use_this: TextSerializationFailure
+general/error_locations/error_location_01: TextSerializationFailure
+general/error_locations/error_location_02: TextSerializationFailure
+general/error_locations/error_location_03: TextSerializationFailure
+general/error_locations/error_location_04: TextSerializationFailure
 general/abstract_members: TypeCheckError
 general/abstract_overrides_concrete_with_no_such_method: TextSerializationFailure
 general/accessors: TextSerializationFailure # Was: RuntimeError
@@ -183,6 +201,7 @@
 general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
 general/override_inference_for_setters: TextSerializationFailure
 general/override_inference_named_parameters_ordering: TextSerializationFailure
+general/override_setter_with_field: TypeCheckError
 general/part_as_entry_point: TextSerializationFailure # Was: Pass
 general/part_as_entry_point_lib: TextSerializationFailure # Was: Pass
 general/part_not_part_of: TextSerializationFailure
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index 8119cab..2c8c9b8 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -1,10 +1,8 @@
 {
-"":"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.md file.",
-
+  "": "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.md file.",
   "packages": "../../.packages",
-
   "suites": [
     {
       "name": "messages",
@@ -12,12 +10,9 @@
       "source": "test/fasta/messages_test.dart",
       "path": "./",
       "status": "messages.status",
-      "pattern": [
-      ],
-      "exclude": [
-      ]
+      "pattern": [],
+      "exclude": []
     },
-
     {
       "name": "scanner",
       "kind": "Chain",
@@ -27,10 +22,8 @@
       "pattern": [
         "\\.dart$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
-
     {
       "name": "parser",
       "kind": "Chain",
@@ -49,7 +42,6 @@
         "/sdk/generated/"
       ]
     },
-
     {
       "name": "outline",
       "kind": "Chain",
@@ -67,11 +59,10 @@
         "/testcases/expression/"
       ]
     },
-
     {
       "name": "strong",
       "kind": "Chain",
-      "source": "test/fasta/strong_test.dart",
+      "source": "test/fasta/strong_tester.dart",
       "path": "testcases/",
       "status": "testcases/strong.status",
       "pattern": [
@@ -85,7 +76,6 @@
         "/testcases/expression/"
       ]
     },
-
     {
       "name": "text_serialization",
       "kind": "Chain",
@@ -103,7 +93,6 @@
         "/testcases/expression/"
       ]
     },
-
     {
       "name": "incremental",
       "kind": "Chain",
@@ -113,8 +102,7 @@
       "pattern": [
         "\\.incremental\\.yaml$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
     {
       "name": "expression",
@@ -125,8 +113,7 @@
       "pattern": [
         "\\.expression\\.yaml$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
     {
       "name": "incremental_load_from_dill",
@@ -137,10 +124,8 @@
       "pattern": [
         "\\.yaml$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
-
     {
       "name": "incremental_bulk_compiler_smoke",
       "kind": "Chain",
@@ -167,10 +152,8 @@
         "/language_2/script2_negative_test\\.dart$",
         "/language_2/unbalanced_brace_test\\.dart$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
-
     {
       "name": "incremental_bulk_compiler_full",
       "kind": "Chain",
@@ -180,10 +163,8 @@
       "pattern": [
         "language_2/.*_test\\.dart$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
-
     {
       "name": "old_dill_test",
       "kind": "Chain",
@@ -193,10 +174,8 @@
       "pattern": [
         ".*\\.dill$"
       ],
-      "exclude": [
-      ]
+      "exclude": []
     },
-
     {
       "name": "lint_test",
       "kind": "Chain",
@@ -210,21 +189,20 @@
         "src/fasta/fasta_codes_generated\\.dart$"
       ]
     },
-
     {
       "name": "spelling_test_src_test",
       "kind": "Chain",
       "source": "test/spelling_test_src_test.dart",
-      "path": "lib/",
+      "path": "../",
       "status": "test/spelling_test.status",
       "pattern": [
-        ".*\\.dart$"
+        "front_end/lib/.*\\.dart$",
+        "kernel/lib/.*\\.dart$"
       ],
       "exclude": [
         "src/fasta/fasta_codes_generated\\.dart$"
       ]
     },
-
     {
       "name": "spelling_test_not_src_test",
       "kind": "Chain",
@@ -272,7 +250,17 @@
         "tool/_fasta/abcompile\\.dart$"
       ]
     },
-
+    {
+      "name": "spelling_test_external_targets",
+      "kind": "Chain",
+      "source": "test/spelling_test_external_targets.dart",
+      "path": "../../",
+      "status": "test/spelling_test.status",
+      "pattern": [
+        ".*\\.dart$"
+      ],
+      "exclude": []
+    },
     {
       "name": "sdk",
       "kind": "Chain",
@@ -300,7 +288,6 @@
         "/sdk/tests/language_2/setter_override_test\\.dart$"
       ]
     },
-
     {
       "note": "Tests dart2js fully, excluding browser-only tests.",
       "name": "dart2js",
@@ -314,7 +301,6 @@
         "-cdart2js -rd8 dart2js_extra dart2js_native"
       ]
     },
-
     {
       "note": "Minimal testing of Fasta.",
       "name": "fasta_min",
@@ -328,7 +314,6 @@
         "-cdartk -rvm"
       ]
     },
-
     {
       "note": "Tests Fasta fully, including the above dart2js tests.",
       "name": "fasta_max",
@@ -343,7 +328,6 @@
         "-cdart2js -rd8 dart2js_extra dart2js_native"
       ]
     },
-
     {
       "note": "Runs dart2js in a mode where it invokes Fasta.",
       "name": "dart2js_with_kernel",
@@ -355,7 +339,6 @@
         "-cdart2js -rd8 --use-sdk --minified language language_2 dart2js_extra dart2js_native corelib corelib_2"
       ]
     },
-
     {
       "name": "type_promotion_look_ahead",
       "kind": "Chain",
@@ -374,12 +357,8 @@
       ]
     }
   ],
-
-
   "analyze": {
-
     "options": "analysis_options_no_lints.yaml",
-
     "uris": [
       "lib/",
       "../analyzer/lib/src/generated/parser_fasta.dart",
@@ -388,16 +367,16 @@
       "../kernel/lib/",
       "../testing/"
     ],
-
     "git grep": {
-      "pathspecs": [ "*.dart" ],
+      "pathspecs": [
+        "*.dart"
+      ],
       "patterns": [
         "package:front_end/",
         "package:kernel/",
         "package:testing/"
       ]
     },
-
     "exclude": [
       "^pkg/analysis_server/lib/src/analysis_server\\.dart",
       "test/extensions/data/",
@@ -409,4 +388,4 @@
       "test/flow_analysis/type_promotion/data/"
     ]
   }
-}
+}
\ No newline at end of file
diff --git a/pkg/front_end/tool/_fasta/bulk_compile.dart b/pkg/front_end/tool/_fasta/bulk_compile.dart
index 79ec59a..c50da92 100644
--- a/pkg/front_end/tool/_fasta/bulk_compile.dart
+++ b/pkg/front_end/tool/_fasta/bulk_compile.dart
@@ -39,7 +39,7 @@
               ..packagesFileUri ??= Uri.base.resolve(".packages")
               ..linkedDependencies = <Uri>[
                 computePlatformBinariesLocation(forceBuildDir: true)
-                    .resolve("vm_platform.dill")
+                    .resolve("vm_platform_strong.dill")
               ]
               ..fileSystem = (new FileBackedMemoryFileSystem()
                 ..entities[mainUri.path] =
diff --git a/pkg/front_end/tool/_fasta/entry_points.dart b/pkg/front_end/tool/_fasta/entry_points.dart
index 4fc6d9d..f9178e3 100644
--- a/pkg/front_end/tool/_fasta/entry_points.dart
+++ b/pkg/front_end/tool/_fasta/entry_points.dart
@@ -304,6 +304,7 @@
 Future<void> compilePlatform(List<String> arguments) async {
   await withGlobalOptions("compile_platform", arguments, false,
       (CompilerContext c, List<String> restArguments) {
+    c.compilingPlatform = true;
     Uri hostPlatform = Uri.base.resolveUri(new Uri.file(restArguments[2]));
     Uri outlineOutput = Uri.base.resolveUri(new Uri.file(restArguments[4]));
     return compilePlatformInternal(
diff --git a/pkg/front_end/tool/fasta.dart b/pkg/front_end/tool/fasta.dart
index 77f1115..a136179 100644
--- a/pkg/front_end/tool/fasta.dart
+++ b/pkg/front_end/tool/fasta.dart
@@ -4,7 +4,9 @@
 
 import 'dart:io';
 
-final String repoDir = _computeRepoDir();
+import '../test/utils/io_utils.dart' show computeRepoDir;
+
+final String repoDir = computeRepoDir();
 
 final String toolDir = '$repoDir/pkg/front_end/tool/_fasta';
 
@@ -94,14 +96,6 @@
   exitCode = await process.exitCode;
 }
 
-String _computeRepoDir() {
-  ProcessResult result = Process.runSync(
-      'git', ['rev-parse', '--show-toplevel'],
-      runInShell: true,
-      workingDirectory: new File.fromUri(Platform.script).parent.path);
-  return (result.stdout as String).trim();
-}
-
 void stop(String message) {
   stderr.write(message);
   exit(2);
diff --git a/pkg/front_end/tool/smoke_test_quick.dart b/pkg/front_end/tool/smoke_test_quick.dart
index 1448d38..9b148a0 100644
--- a/pkg/front_end/tool/smoke_test_quick.dart
+++ b/pkg/front_end/tool/smoke_test_quick.dart
@@ -2,15 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+import 'dart:io' show Platform, Process, ProcessResult, exitCode;
 
-final String repoDir = _computeRepoDir();
+import '../test/utils/io_utils.dart' show computeRepoDir;
+
+final String repoDir = computeRepoDir();
 
 String get dartVm => Platform.executable;
 
 main(List<String> args) async {
   Stopwatch stopwatch = new Stopwatch()..start();
   List<Future> futures = new List<Future>();
+  futures.add(
+      run("pkg/front_end/test/explicit_creation_test.dart", [], filter: false));
   futures.add(run(
     "pkg/front_end/test/fasta/messages_test.dart",
     ["-DfastOnly=true"],
@@ -18,6 +22,7 @@
   futures.add(run("pkg/front_end/test/spelling_test_not_src_test.dart", []));
   futures.add(run("pkg/front_end/test/spelling_test_src_test.dart", []));
   futures.add(run("pkg/front_end/test/lint_test.dart", []));
+  futures.add(run("pkg/front_end/test/deps_test.dart", [], filter: false));
   await Future.wait(futures);
   print("\n-----------------------\n");
   print("Done with exitcode $exitCode in ${stopwatch.elapsedMilliseconds} ms");
@@ -51,18 +56,18 @@
     }
     stdout = stdout.trim();
     if (stdout.isNotEmpty) {
+      print("--- stdout start ---");
       print(stdout);
-      print("-----");
+      print("--- stdout end ---");
+    }
+
+    String stderr = result.stderr.toString().trim();
+    if (stderr.isNotEmpty) {
+      print("--- stderr start ---");
+      print(stderr);
+      print("--- stderr end ---");
     }
   } else {
     print("Running: $runWhat: Done in ${stopwatch.elapsedMilliseconds} ms.");
   }
 }
-
-String _computeRepoDir() {
-  ProcessResult result = Process.runSync(
-      'git', ['rev-parse', '--show-toplevel'],
-      runInShell: true,
-      workingDirectory: new File.fromUri(Platform.script).parent.path);
-  return (result.stdout as String).trim();
-}
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index 81bfe53..8285315 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -20,7 +20,6 @@
 import 'package:kernel/transformations/empty.dart' as empty;
 import 'package:kernel/transformations/method_call.dart' as method_call;
 import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
-import 'package:kernel/transformations/coq.dart' as coq;
 import 'package:kernel/vm/constants_native_effects.dart';
 
 ArgParser parser = new ArgParser()
@@ -98,9 +97,6 @@
       mix.transformLibraries(
           new NoneTarget(null), coreTypes, hierarchy, component.libraries);
       break;
-    case 'coq':
-      component = coq.transformComponent(coreTypes, component);
-      break;
     case 'constants':
       final VmConstantsBackend backend = new VmConstantsBackend(coreTypes);
       component = constants.transformComponent(
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 267cdf4..cad20ee 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -57,7 +57,7 @@
 
 type RList<T> {
   T[length] elements;
-  Uint32 length;
+  UInt32 length;
 }
 
 // Untagged pairs.
@@ -101,6 +101,10 @@
   List<Byte> importUriUtf8Bytes;
 }
 
+type String {
+  List<Byte> utf8Bytes;
+}
+
 type UriSource {
   UInt32 length;
   SourceInfo[length] source;
@@ -139,7 +143,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 29;
+  UInt32 formatVersion = 31;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
   UriSource sourceMap;
@@ -168,6 +172,7 @@
 // which allows to skip to any other field in this component index,
 // which again allows to skip to what it points to.
 type ComponentIndex {
+  Byte[] 8bitAlignment; // 0-bytes to make the entire component (!) 8-byte aligned.
   UInt32 binaryOffsetForSourceTable;
   UInt32 binaryOffsetForCanonicalNames;
   UInt32 binaryOffsetForMetadataPayloads;
@@ -237,6 +242,7 @@
   List<LibraryPart> libraryParts;
   List<Typedef> typedefs;
   List<Class> classes;
+  List<Extension> extensions;
   List<Field> fields;
   List<Procedure> procedures;
 
@@ -274,8 +280,8 @@
   List<TypeParameter> typeParameters;
   DartType type;
   List<TypeParameter> typeParametersOfFunctionType;
-  List<VariableDeclaration> positionalParameters;
-  List<VariableDeclaration> namedParameters;
+  List<VariableDeclarationPlain> positionalParameters;
+  List<VariableDeclarationPlain> namedParameters;
 }
 
 type Combinator {
@@ -331,6 +337,26 @@
   UInt32 procedureCount = procedures.length;
 }
 
+type Extension extends Node {
+  Byte tag = 115;
+  CanonicalNameReference canonicalName;
+  StringReference name;
+  UriReference fileUri;
+  FileOffset fileOffset;
+  List<TypeParameter> typeParameters;
+  DartType onType;
+  List<ExtensionMemberDescriptor> members;
+}
+
+enum ExtensionMemberKind { Field = 0, Method = 1, Getter = 2, Setter = 3, Operator = 4, TearOff = 5, }
+
+type ExtensionMemberDescriptor {
+  StringReference name;
+  ExtensionMemberKind kind;
+  Byte flags (isStatic, isExternal);
+  MemberReference member;
+}
+
 abstract type Member extends Node {}
 
 type Field extends Member {
@@ -381,7 +407,7 @@
   FileOffset fileOffset; // Offset of the procedure name.
   FileOffset fileEndOffset;
   Byte kind; // Index into the ProcedureKind enum above.
-  Uint flags (isStatic, isAbstract, isExternal, isConst, isForwardingStub,
+  UInt flags (isStatic, isAbstract, isExternal, isConst, isForwardingStub,
               isForwardingSemiStub, isRedirectingFactoryConstructor,
               isNoSuchMethodForwarder, isExtensionMember);
   Name name;
@@ -394,7 +420,7 @@
 }
 
 type RedirectingFactoryConstructor extends Member {
-  Byte tag = 107;
+  Byte tag = 108;
   CanonicalNameReference canonicalName;
   UriReference fileUri;
   FileOffset fileOffset;
@@ -407,8 +433,8 @@
   List<TypeParameter> typeParameters;
   UInt parameterCount; // positionalParameters.length + namedParameters.length.
   UInt requiredParameterCount;
-  List<VariableDeclaration> positionalParameters;
-  List<VariableDeclaration> namedParameters;
+  List<VariableDeclarationPlain> positionalParameters;
+  List<VariableDeclarationPlain> namedParameters;
 }
 
 abstract type Initializer extends Node {}
@@ -444,7 +470,7 @@
 type LocalInitializer extends Initializer {
   Byte tag = 11;
   Byte isSynthetic;
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
 }
 
 type AssertInitializer extends Initializer {
@@ -472,8 +498,8 @@
   List<TypeParameter> typeParameters;
   UInt parameterCount; // positionalParameters.length + namedParameters.length.
   UInt requiredParameterCount;
-  List<VariableDeclaration> positionalParameters;
-  List<VariableDeclaration> namedParameters;
+  List<VariableDeclarationPlain> positionalParameters;
+  List<VariableDeclarationPlain> namedParameters;
   DartType returnType;
   Option<Statement> body;
 }
@@ -729,11 +755,18 @@
   FileOffset fileOffset;
   CanonicalNameReference class;
   List<DartType> typeArguments;
-  List<[FieldReference, Expression]> fieldValues;
+  List<Pair<FieldReference, Expression>> fieldValues;
   List<AssertStatement> asserts;
   List<Expression> unusedArguments;
 }
 
+type FileUriExpression extends Expression {
+  Byte tag = 116;
+  UriReference fileUri;
+  FileOffset fileOffset;
+  Expression expression;
+}
+
 type IsExpression extends Expression {
   Byte tag = 37;
   FileOffset fileOffset;
@@ -754,22 +787,24 @@
   StringReference value;
 }
 
-type SpecializedIntLiteral extends Expression {
+type IntegerLiteral extends Expression {}
+
+type SpecializedIntLiteral extends IntegerLiteral {
   Byte tag = 144 + N; // Where 0 <= N < 8.
   // Integer literal with value (N - 3), that is, an integer in range -3..4.
 }
 
-type PositiveIntLiteral extends Expression {
+type PositiveIntLiteral extends IntegerLiteral {
   Byte tag = 55;
   UInt value;
 }
 
-type NegativeIntLiteral extends Expression {
+type NegativeIntLiteral extends IntegerLiteral {
   Byte tag = 56;
   UInt absoluteValue;
 }
 
-type BigIntLiteral extends Expression {
+type BigIntLiteral extends IntegerLiteral {
   Byte tag = 57;
   StringReference valueString;
 }
@@ -879,7 +914,7 @@
 
 type Let extends Expression {
   Byte tag = 53;
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
   Expression body;
 }
 
@@ -912,13 +947,10 @@
   ConstantReference constantReference;
 }
 
-type Deprecated_ConstantExpression extends Expression {
-  Byte tag = 107;
-  ConstantReference constantReference;
+abstract type Constant extends Node {
+  Byte tag;
 }
 
-abstract type Constant extends Node {}
-
 type NullConstant extends Constant {
   Byte tag = 0;
 }
@@ -930,7 +962,7 @@
 
 type IntConstant extends Constant {
   Byte tag = 2;
-  PositiveIntLiteral | NegativeIntLiteral | SpecializedIntLiteral | BigIntLiteral value;
+  IntegerLiteral value;
 }
 
 type DoubleConstant extends Constant {
@@ -953,7 +985,7 @@
   Byte tag = 6;
   DartType keyType;
   DartType valueType;
-  List<[ConstantReference, ConstantReference]> keyValueList;
+  List<Pair<ConstantReference, ConstantReference>> keyValueList;
 }
 
 type ListConstant extends Constant {
@@ -972,7 +1004,7 @@
   Byte tag = 8;
   CanonicalNameReference class;
   List<DartType> typeArguments;
-  List<[FieldReference, ConstantReference]> values;
+  List<Pair<FieldReference, ConstantReference>> values;
 }
 
 type PartialInstantiationConstant extends Constant {
@@ -1058,7 +1090,7 @@
 type ForStatement extends Statement {
   Byte tag = 69;
   FileOffset fileOffset;
-  List<VariableDeclaration> variables;
+  List<VariableDeclarationPlain> variables;
   Option<Expression> condition;
   List<Expression> updates;
   Statement body;
@@ -1068,7 +1100,7 @@
   Byte tag = 70;
   FileOffset fileOffset;
   FileOffset bodyOffset;
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
   Expression iterable;
   Statement body;
 }
@@ -1077,7 +1109,7 @@
   Byte tag = 80; // Note: tag is out of order.
   FileOffset fileOffset;
   FileOffset bodyOffset;
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
   Expression iterable;
   Statement body;
 }
@@ -1137,8 +1169,8 @@
 type Catch {
   FileOffset fileOffset;
   DartType guard;
-  Option<VariableDeclaration> exception;
-  Option<VariableDeclaration> stackTrace;
+  Option<VariableDeclarationPlain> exception;
+  Option<VariableDeclarationPlain> stackTrace;
   Statement body;
 }
 
@@ -1155,12 +1187,12 @@
   Expression expression;
 }
 
-type VariableDeclarationStatement extends Statement {
+type VariableDeclaration extends Statement {
   Byte tag = 78;
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
 }
 
-type VariableDeclaration {
+type VariableDeclarationPlain {
   // The offset for the variable declaration, i.e. the offset of the start of
   // the declaration.
   FileOffset fileOffset;
@@ -1192,7 +1224,7 @@
   // within the function for use as a self-reference.
   // Some of the fields in the variable are redundant, but its presence here
   // simplifies the rule for variable indexing.
-  VariableDeclaration variable;
+  VariableDeclarationPlain variable;
   FunctionNode function;
 }
 
@@ -1200,6 +1232,10 @@
 
 abstract type DartType extends Node {}
 
+type BottomType extends DartType {
+  Byte tag = 89;
+}
+
 type InvalidType extends DartType {
   Byte tag = 90;
 }
@@ -1243,7 +1279,6 @@
   Byte tag = 97; // Note: tag is out of order.
   Byte nullability; // Index into the Nullability enum above.
   List<DartType> positionalParameters;
-  List<StringReference> positionalParameterNames;
   DartType returnType;
   // Equivalent to a FunctionType with no type parameters or named parameters,
   // and where all positional parameters are required.
diff --git a/pkg/kernel/coq/Common.v b/pkg/kernel/coq/Common.v
deleted file mode 100644
index 38653bc..0000000
--- a/pkg/kernel/coq/Common.v
+++ /dev/null
@@ -1,190 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file. *)
-
-Require Export List.
-Require Export Coq.FSets.FMapWeakList.
-Require Export Coq.FSets.FMapFacts.
-Require Export Coq.Structures.DecidableTypeEx.
-Require Export Coq.Structures.Equalities.
-Require Export Coq.Strings.String.
-Require Import CpdtTactics.
-
-(** * Auxiliary definitions. *)
-
-(** Strings are used as keys in maps of getters, setters, and methods of
-  interface types.  For maps we use the list-based unordered representation,
-  because it only requires decidability on the domain of keys.  [String_as_MDT]
-  and [String_as_UDT] below are auxiliary modules to define [StringMap]. *)
-
-Module String_as_MDT.
-  Definition t := string.
-  Definition eq_dec := string_dec.
-End String_as_MDT.
-
-Module String_as_UDT := Equalities.Make_UDT(String_as_MDT).
-
-(** [NatMap] is used to map type variables to type locations and to map type
-  locations to type values. *)
-Module NatMap := FMapWeakList.Make(Nat_as_DT).
-Module NatMapFacts := FMapFacts.Facts NatMap.
-
-(** [StringMap] is used to map identifiers to getters, setters, and methods. *)
-Module StringMap := FMapWeakList.Make(String_as_UDT).
-
-(* A "comp A" denotes a partial function that may not terminate on some inputs
-   or terminate without an answer on others. *)
-Module ComputationMonad.
-
-  Definition comp (A : Type) := nat -> option A.
-
-  Definition comp_return {A : Type} (a : A) : comp A := fun _ => Some a.
-  Definition abort {A : Type} : comp A := fun _ => None.
-
-  Definition comp_bind {A : Type} {B : Type} (x : comp A) (y : A -> comp B) : comp B :=
-    fun n => match x n with None => None | Some a => y a n end.
-  Definition comp_unsome {A : Type} (v : option A) : comp A := fun _ => v.
-
-  Notation "[ x ]" := (comp_return x) (at level 0, x at level 200).
-  Notation "[[ x ]]" := (comp_unsome x) (at level 0, x at level 99).
-  Notation "x <- m1 ; m2" := (comp_bind m1 (fun x => m2)) (at level 70, right associativity).
-
-  Fixpoint comp_fix' (A : Type) (B : Type) (f : (A -> comp B) -> (A -> comp B)) (a : A) (n : nat) {struct n} : option B :=
-    match n with
-    | O => None
-    | (S n) => let rec := fun (a : A) => comp_unsome (comp_fix' _ _ f a n) in f rec a n
-    end.
-
-  Definition Fix {A : Type} {B : Type} (f : (A -> comp B) -> (A -> comp B)) : A -> comp B :=
-    fun a => fun n => comp_fix' _ _ f a n.
-
-  Module Continuity.
-
-    Definition continuous {A: Type} (f: comp A) : Prop :=
-      forall n k v, n <= k -> f n = Some v -> f k = Some v.
-
-    Lemma return_cont {A: Type} : forall a : A, continuous (comp_return a).
-      intros.
-      unfold comp_return.
-      unfold continuous.
-      auto.
-    Qed.
-
-    Lemma abort_cont {A : Type} : continuous (@abort A).
-      unfold abort.
-      unfold continuous.
-      auto.
-    Qed.
-
-  End Continuity.
-
-End ComputationMonad.
-
-Module OptionMonad.
-
-  Notation "[ x ]" := (Some x) (at level 0, x at level 200).
-
-  Definition opt_bind {A B} (x : option A) (f : A -> option B) : option B :=
-    match x with
-    | None => None
-    | Some v => f v
-    end.
-
-  Notation "x <- m1 ; m2" := (opt_bind m1 (fun x => m2)) (at level 70, right associativity).
-
-End OptionMonad.
-
-Module ListExtensions.
-  Import ComputationMonad.
-
-  Fixpoint mmap {A B} (f : A -> comp B) (l : list A) : comp (list B) :=
-    match l with
-    | nil => [nil]
-    | (x::xs) => (x' <- f x; xs' <- mmap f xs; [x' :: xs'])
-    end.
-
-  Lemma foldr_mono {A} {B} :
-    forall (P : A -> A -> Prop) (l : list B) (a0 : A) (f : B -> A -> A),
-      (forall x, P x x) ->
-      (forall x y z, P x y -> P y z -> P x z) ->
-      (forall a b, P a (f b a)) ->
-      P a0 (List.fold_right f a0 l).
-  Proof.
-    induction l; crush.
-    pose proof (IHl a0 f H H0 H1).
-    pose proof (H1 (fold_right f a0 l) a).
-    pose proof (H0 _ _ _ H2 H3).
-    crush.
-  Qed.
-
-  Lemma foldr_preserve {A} {B} :
-    forall (P : A -> Prop) (l : list B) (a0 : A) (f : B -> A -> A),
-      (forall a b, P a -> P (f b a)) ->
-      P a0 -> P (List.fold_right f a0 l).
-  Proof.
-    induction l; crush.
-  Qed.
-
-  Fixpoint list_all {A} (f : A -> Prop) (l : list A) :=
-    match l with
-    | nil => True
-    | (x::xs) => f x /\ list_all f xs
-    end.
-
-  Lemma forall_list_all : forall A P (l : list A), Forall P l <-> list_all P l.
-    intros.
-    apply conj.
-    intro f.
-    induction f; crush.
-    induction l; crush.
-  Qed.
-End ListExtensions.
-
-(* These could be generalized and factored into a functor, like FMapFacts, but
- * right now there's no need. *)
-Module MoreNatMapFacts.
-
-Module N := Coq.Arith.PeanoNat.Nat.
-
-Lemma add_3 {A} : forall m x (y y' : A), NatMap.MapsTo x y m /\ NatMap.MapsTo x y' m -> y = y'.
-  intuition.
-  set (Fx := NatMap.find x m).
-  assert (Fx = NatMap.find x m) by auto.
-  pose proof (NatMap.find_1 H0).
-  pose proof (NatMap.find_1 H1).
-  crush.
-Qed.
-
-Lemma maps_in_mapsto :
-  forall A (m : NatMap.t A) key,
-  NatMap.In key m ->
-  exists el, NatMap.MapsTo key el m.
-Proof.
-  intros.
-  pose proof (NatMapFacts.find_mapsto_iff m key).
-  pose proof (NatMapFacts.in_find_iff m key).
-    unfold iff in H1. destruct H1 as [H1a H1b].
-  pose proof (H1a H).
-  destruct (NatMap.find key m) eqn:?.
-    exists a. pose proof (H0 a). unfold iff in H2. destruct H2 as [H2a H2b].
-      apply H2b. congruence.
-    contradiction.
-Qed.
-
-Lemma maps_mapsto_in :
-  forall A (m : NatMap.t A) key,
-  (exists el, NatMap.MapsTo key el m) ->
-  NatMap.In key m.
-Proof.
-  intros.
-  destruct H as (el & H1).
-  pose proof (NatMapFacts.find_mapsto_iff m key el).
-  unfold iff in H. destruct H as [H2 H3].
-  pose proof (H2 H1).
-  assert (Some el <> None). discriminate.
-  rewrite <- H in H0.
-  apply NatMapFacts.in_find_iff in H0.
-  auto.
-Qed.
-
-End MoreNatMapFacts.
diff --git a/pkg/kernel/coq/CommonTactics.v b/pkg/kernel/coq/CommonTactics.v
deleted file mode 100644
index 6a92448..0000000
--- a/pkg/kernel/coq/CommonTactics.v
+++ /dev/null
@@ -1,75 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file. *)
-
-Require Import Common.
-Require Export CpdtTactics.
-
-Import OptionMonad.
-
-Ltac extract E x y := set (x := E); assert (y : E = x); [auto|rewrite y in *].
-
-Ltac force_expr E H :=
-  let v1 := fresh in
-  let v2 := fresh in
-  extract E v1 v2; destruct v1; [idtac|simpl in H; contradict H; congruence].
-
-Lemma bind_some : forall A B x f, @opt_bind A B (Some x) f = f x.
-Proof.
-  auto.
-Qed.
-
-Lemma simpl_if : forall A (e1 e2 : A), (if true then e1 else e2) = e1.
-  auto.
-Qed.
-
-    (* remember (expression_type CE (NatMap.add v s TE) arg) as EXP. *)
-(* destruct EXP; [rewrite bind_some in H1|simpl in H1; contradict H1; congruence]. *)
-Ltac force_option :=
-  match goal with
-  | [ H : (opt_bind ?y (fun x => ?z)) = Some ?w |- _ ] =>
-    force_expr y H; rewrite bind_some in H
-  | [ H : (if ?cond then ?x else None) = Some ?w |- _ ] =>
-    force_expr cond H; rewrite simpl_if in H
-  | [ H : (match ?x with _ => _ end) = Some ?w |- _ ] =>
-    force_expr x H
-  end.
-
-Ltac force_options := repeat force_option.
-
-Inductive ltac_no_arg : Set :=
-| Ltac_No_Arg : ltac_no_arg.
-
-Ltac extract_head_2 term H varid eqid :=
-  match type of H with
-  | context[term ?X] => extract_head_2 (term X) H varid eqid
-  | context[term] => remember term as varid eqn:eqid
-  end.
-
-Ltac extract_head_1 term H varid := let eqid := fresh varid "Eq" in extract_head_2 term H varid eqid.
-Ltac extract_head_0 term H := let varid := fresh H in extract_head_1 term H varid.
-
-Ltac extract_head_goal_2 term varid eqid :=
-  match goal with
-  | [ |- context[term ?X] ] => extract_head_goal_2 (term X) varid eqid
-  | [ |- context[term] ] => remember term as varid eqn:eqid
-  end.
-
-Ltac extract_head_goal_1 term varid := let eqid := fresh varid "Eq" in extract_head_goal_2 term varid eqid.
-Ltac extract_head_goal_0 term := let varid := fresh "G" in extract_head_goal_1 term varid.
-
-Tactic Notation "extract_head" constr(term) "in" constr(H) := extract_head_0 term H.
-Tactic Notation "extract_head" constr(term) "in" constr(H) "as" ident(name) := extract_head_1 term H name.
-Tactic Notation "extract_head" constr(term) "in" constr(H) "as" ident(name) "," ident(name2) := extract_head_2 term H name name2.
-
-Tactic Notation "extract_head" constr(term) := extract_head_goal_0 term.
-Tactic Notation "extract_head" constr(term) "as" ident(name) := extract_head_goal_1 term name.
-Tactic Notation "extract_head" constr(term) "as" ident(name) "," ident(name2) := extract_head_goal_2 term name name2.
-
-Ltac continue_with H :=
-  match type of H with
-  | ?X -> ?Y =>
-    let K := fresh H in
-    let H' := fresh H in
-    assert (X) as K; [idtac|pose proof (H K) as H']
-  end.
diff --git a/pkg/kernel/coq/ObjectModel.v b/pkg/kernel/coq/ObjectModel.v
deleted file mode 100644
index 746b72e..0000000
--- a/pkg/kernel/coq/ObjectModel.v
+++ /dev/null
@@ -1,1057 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file. *)
-
-Require Import Common.
-Require Import CommonTactics.
-Require Import Syntax.
-Require Import Coq.Strings.String.
-(* This is for convenience, we could remove it with some refactoring if we so wished. *)
-Require Import Coq.Logic.FunctionalExtensionality.
-
-Import Common.OptionMonad.
-Import Common.ListExtensions.
-Import Common.NatMapFacts.
-Import Common.MoreNatMapFacts.
-
-Module N := Coq.Arith.PeanoNat.Nat.
-
-(* The subtyping function doesn't satisfy the ordinary subterm totality
-   condition due to the contravariant property function parameter types.
-   Instead, we prove it terminates by induction on the sum of both types'
-   syntactic sizes. *)
-Section Dart_Type_Pair_Size_Properties.
-  Fixpoint size (d : dart_type) : nat :=
-    match d with
-    | DT_Interface_Type (Interface_Type n) => 1
-    | DT_Function_Type (Function_Type p r) => size p + size r + 1
-    end.
-
-  Definition pair_size (d : dart_type * dart_type) :=
-    let (x, y) := d in size x + size y.
-
-  Definition pair_size_order (d e : dart_type * dart_type) := pair_size d < pair_size e.
-  Hint Constructors Acc.
-  Lemma pair_size_order_wf' : forall sz, forall d, pair_size d < sz -> Acc pair_size_order d.
-  Proof.
-    unfold pair_size_order; induction sz; crush.
-  Defined.
-  Theorem pair_size_order_wf : well_founded pair_size_order.
-    red; intros; eapply pair_size_order_wf'; eauto.
-  Defined.
-End Dart_Type_Pair_Size_Properties.
-
-Module Subtyping.
-
-  Local Definition subtype_rec
-    (p : dart_type * dart_type)
-    (subtype : forall p' : dart_type * dart_type, pair_size_order p' p -> bool) : bool.
-    refine (
-        match p as p' return (p = p' -> bool) with
-        | (DT_Interface_Type (Interface_Type s_class),
-           DT_Interface_Type (Interface_Type t_class)) =>
-          fun H1 => N.eqb s_class t_class
-        | (DT_Function_Type (Function_Type s_param s_ret),
-           DT_Function_Type (Function_Type t_param t_ret)) =>
-          fun H2 => andb (subtype (t_param, s_param) _) (subtype (s_ret, t_ret) _)
-        | _ => fun _ => false
-        end (eq_refl : p = p));
-    destruct p;
-    destruct d1; destruct d2; crush;
-    unfold pair_size_order;
-    crush.
-  Defined.
-
-  Definition subtype : dart_type * dart_type -> bool :=
-    Fix pair_size_order_wf (fun _ => bool) subtype_rec.
-
-  Notation "s ◁ t" := (subtype (s, t) = true) (at level 70, no associativity).
-
-  Local Ltac destruct_types :=
-    repeat match goal with
-           | [H : interface_type |- _] => destruct H
-           | [H : function_type |- _] => destruct H
-           end.
-
-  Local Lemma subtype_rec_equiv :
-    forall (x : dart_type * dart_type)
-           (f g : forall y : dart_type * dart_type, pair_size_order y x -> bool),
-      (forall (y : dart_type * dart_type) (p : pair_size_order y x), f y p = g y p) ->
-      subtype_rec x f = subtype_rec x g.
-  Proof.
-    intros;
-      destruct x;
-      destruct d;
-      destruct d0;
-      destruct_types;
-      cbv;
-      crush.
-  Qed.
-
-  Definition subtype_rewrite :=
-    Fix_eq pair_size_order_wf (fun _ => bool) subtype_rec subtype_rec_equiv.
-
-  Local Ltac unfold_subtype' H :=
-    match type of H with
-    | ltac_no_arg =>
-      unfold subtype;
-      rewrite subtype_rewrite;
-      unfold subtype_rec at 1;
-      fold subtype
-    | _ =>
-      unfold subtype in H;
-      rewrite subtype_rewrite in H;
-      unfold subtype_rec at 1 in H;
-      fold subtype in H
-    end.
-
-  Tactic Notation "unfold_subtype" := unfold_subtype' Ltac_No_Arg.
-  Tactic Notation "unfold_subtype" constr(x) := unfold_subtype' x.
-
-  Hint Rewrite N.eqb_eq.
-  Hint Unfold subtype.
-
-  Lemma subtype_refl : forall s : dart_type, s ◁ s.
-    apply
-      (dart_type_ind_mutual
-         (fun s => s ◁ s)
-         (fun i => DT_Interface_Type i ◁ DT_Interface_Type i)
-         (fun f => DT_Function_Type f ◁ DT_Function_Type f)); crush.
-    cbv; crush.
-    unfold_subtype; crush.
-  Qed.
-
-  Definition trans_at t := forall s r, s ◁ t /\ t ◁ r -> s ◁ r.
-
-  Hint Unfold trans_at.
-
-  (* TODO(sjindel): how can we generalize this? *)
-  Ltac simplify_subtypes :=
-    repeat ( intuition; repeat ( destruct_types || match goal with
-    | [ H : DT_Interface_Type (Interface_Type _) ◁ _ |- _ ] =>
-      unfold_subtype H
-    | [ H : DT_Function_Type (Function_Type _ _) ◁ _ |- _ ] =>
-      unfold_subtype H
-    | [ H : _ ◁ DT_Interface_Type (Interface_Type _) |- _ ] =>
-      unfold_subtype H
-    | [ H : _ ◁ DT_Function_Type (Function_Type _ _) |- _ ] =>
-      unfold_subtype H
-    | [ |- DT_Interface_Type (Interface_Type _) ◁ _ ] =>
-      unfold_subtype
-    | [ |- DT_Function_Type (Function_Type _ _) ◁ _ ] =>
-      unfold_subtype
-    | [ |- _ ◁ DT_Interface_Type (Interface_Type _) ] =>
-      unfold_subtype
-    | [ |- _ ◁ DT_Function_Type (Function_Type _ _) ] =>
-      unfold_subtype
-  end)).
-
-  Local Lemma interface_type_trans : forall (n : nat), trans_at (DT_Interface_Type (Interface_Type n)).
-  Proof.
-    intros.
-    unfold trans_at.
-    intros.
-    destruct s; destruct r; simplify_subtypes; crush.
-  Qed.
-  Hint Immediate interface_type_trans.
-
-  Local Lemma function_type_trans :
-    forall d, trans_at d -> forall d', trans_at d' ->
-    trans_at (DT_Function_Type (Function_Type d d')).
-  Proof.
-    intros; unfold trans_at in *; intros; destruct s; destruct r.
-    crush.
-    simplify_subtypes.
-    crush.
-    simplify_subtypes.
-    rewrite Bool.andb_true_iff in *.
-    crush.
-  Qed.
-  Hint Immediate function_type_trans.
-
-  Lemma subtype_trans : forall t s r, s ◁ t /\ t ◁ r -> s ◁ r.
-    apply (dart_type_induction trans_at); crush.
-  Qed.
-  Hint Resolve subtype_trans.
-
-End Subtyping.
-Import Subtyping.
-
-Record procedure_desc : Type := mk_procedure_desc {
-  pr_name : string;
-  pr_ref : nat;
-  pr_type : function_type;
-}.
-
-Record getter_desc : Type := mk_getter_desc {
-  gt_name : string;
-  gt_ref : nat;
-  gt_type : dart_type;
-}.
-
-Record interface : Type := mk_interface {
-  procedures : list procedure_desc;
-  getters    : list getter_desc;
-}.
-
-Inductive member_desc : Type :=
-  | MD_Method : procedure_desc -> member_desc
-  | MD_Getter : getter_desc -> member_desc
-.
-
-(** Type envronment maps class IDs to their interface type. *)
-Definition class_env : Type := NatMap.t interface.
-
-Definition type_env : Type := NatMap.t dart_type.
-
-Fixpoint expression_type
-    (CE : class_env) (TE : type_env) (e : expression) :
-    option dart_type :=
-  match e with
-  | E_Variable_Get (Variable_Get v) => NatMap.find v TE
-  | E_Property_Get (Property_Get rec prop) =>
-    rec_type <- expression_type CE TE rec;
-    let (prop_name) := prop in
-    match rec_type with
-    | DT_Function_Type _ =>
-      if string_dec prop_name "call" then [rec_type] else None
-    | DT_Interface_Type (Interface_Type class) =>
-      interface <- NatMap.find class CE;
-      proc_desc <- List.find (fun P =>
-        if string_dec (pr_name P) prop_name then true else false)
-        (procedures interface);
-      [DT_Function_Type (pr_type proc_desc)]
-    end
-  | E_Invocation_Expression (IE_Constructor_Invocation (Constructor_Invocation class)) =>
-    _ <- NatMap.find class CE;
-    [DT_Interface_Type (Interface_Type class)]
-  | E_Invocation_Expression (IE_Method_Invocation (Method_Invocation rec method args _)) =>
-    rec_type <- expression_type CE TE rec;
-    let (arg_exp) := args in
-    arg_type <- expression_type CE TE arg_exp;
-    let (method_name) := method in
-    fun_type <-
-      match rec_type with
-      | DT_Function_Type fn_type =>
-        if string_dec "call" method_name then [fn_type] else None
-      | DT_Interface_Type (Interface_Type class) =>
-        interface <- NatMap.find class CE;
-        proc_desc <- List.find (fun P =>
-          if string_dec (pr_name P) method_name then true else false)
-          (procedures interface);
-        [pr_type proc_desc]
-      end;
-    let (param_type, ret_type) := fun_type in
-    if subtype (arg_type, param_type) then [ret_type] else None
-  end
-.
-
-Fixpoint statement_type (CE : class_env) (TE : type_env) (s : statement) (r: dart_type) :
-    option type_env :=
-  match s with
-  | S_Expression_Statement (Expression_Statement e) =>
-    _ <- expression_type CE TE e; [TE]
-  | S_Return_Statement (Return_Statement re) =>
-    rt <- expression_type CE TE re;
-    if subtype (rt, r) then [TE] else None
-  | S_Variable_Declaration (Variable_Declaration _ _ None) => None
-  | S_Variable_Declaration (Variable_Declaration var type (Some init)) =>
-    init_type <- expression_type CE TE init;
-    if subtype (init_type, type) then
-      [NatMap.add var type TE]
-    else
-      None
-  | S_Block (Block stmts) =>
-    let process_statements := fix process_statements TE stmts :=
-      match stmts with
-      | nil => [TE]
-      | (s::ss) =>
-        TE' <- statement_type CE TE s r;
-        process_statements TE' ss
-      end in
-    process_statements TE stmts
-  end
-.
-
-Definition procedure_type (CE : class_env) (p : procedure) : bool :=
-  let (_, _, fn) := p in
-  let (param, ret_type, body) := fn in
-  let (param_var, param_type, _) := param in
-  let TE := NatMap.add param_var param_type (NatMap.empty _) in
-  match statement_type CE TE body ret_type with Some _ => true | None => false end
-.
-
-Definition class_type (CE : class_env) (c : class) : bool :=
-  let (nn_data, _, procedures) := c in
-  forallb (procedure_type CE) procedures
-.
-
-Section Typing_Equivalence_Homomorphism.
-
-  Definition subtype_at (e : expression) :=
-    forall CE TE v s t es,
-                 expression_type CE (NatMap.add v s TE) e = [es] /\ t ◁ s ->
-      exists et, expression_type CE (NatMap.add v t TE) e = [et] /\ et ◁ es.
-
-  Hint Resolve NatMap.add_1.
-  Hint Resolve NatMap.add_2.
-  Hint Resolve NatMap.find_1.
-  Hint Resolve subtype_refl.
-  Lemma subtype_at_variable_get :
-    forall v, subtype_at (E_Variable_Get (Variable_Get v)).
-  Proof.
-    unfold subtype_at.
-    intros.
-    destruct (N.eq_dec v v0).
-    rewrite e in *.
-    exists t.
-    assert (es = s).
-    unfold expression_type in H.
-    assert (NatMap.find v0 (NatMap.add v0 s TE) = Some s) by crush.
-    rewrite H0 in H.
-    crush.
-    intuition.
-    unfold expression_type.
-    crush.
-    crush.
-    destruct H.
-    unfold expression_type in H.
-    apply NatMap.find_2 in H.
-    exists es.
-    unfold expression_type in *.
-    pose proof (@NatMap.add_3 dart_type TE v0 v es s (not_eq_sym n) H).
-    crush.
-  Qed.
-  Hint Immediate subtype_at_variable_get.
-
-  Hint Rewrite N.eqb_eq.
-  Lemma subtype_at_property_get :
-    forall rec prop, subtype_at rec -> subtype_at (E_Property_Get (Property_Get rec prop)).
-  Proof.
-    unfold subtype_at.
-    intros.
-    intuition.
-    destruct prop.
-    unfold expression_type in H1.
-    fold expression_type in H1.
-    extract (expression_type CE (NatMap.add v s TE) rec) Orig H0.
-
-    (* Go by cases on the original type of the receiver. *)
-    destruct Orig; [idtac|crush].
-    simpl in H1.
-    destruct d.
-
-    (* Case 1: receiver has interface type. *)
-    destruct i.
-    extract (NatMap.find n CE) iface H3.
-    destruct iface; [idtac|crush].
-    simpl in H1.
-    pose proof (H CE TE v s t (DT_Interface_Type (Interface_Type n)) (conj H0 H2)).
-    destruct H4 as [new_rec_type].
-    destruct H4.
-    destruct new_rec_type.
-    destruct i0.
-    unfold_subtype H5.
-    exists es.
-    crush.
-    unfold_subtype H5.
-    destruct f.
-    crush.
-
-    (* Case 2: receiver has function type. *)
-    destruct f.
-    force_options.
-    pose proof (H CE TE v s t (DT_Function_Type (Function_Type d d0)) (conj H0 H2)).
-    destruct H3 as [new_rec_type].
-    destruct H3.
-    exists new_rec_type.
-    intuition; [idtac|crush].
-    unfold expression_type.
-    fold expression_type.
-    rewrite H3.
-    simpl.
-    destruct new_rec_type.
-    destruct i.
-    unfold_subtype H5.
-    crush.
-    crush.
-  Qed.
-  Hint Immediate subtype_at_property_get.
-
-  Lemma subtype_at_ctor_invo :
-    forall c, subtype_at (E_Invocation_Expression (IE_Constructor_Invocation c)).
-  Proof.
-    unfold subtype_at; intros; exists es; crush.
-  Qed.
-  Hint Immediate subtype_at_ctor_invo.
-
-  Lemma subtype_at_meth_invo :
-    forall rec arg name n, subtype_at rec -> subtype_at arg ->
-      subtype_at (E_Invocation_Expression (IE_Method_Invocation (Method_Invocation rec name (Arguments arg) n))).
-  Proof.
-    unfold subtype_at; intros.
-    unfold expression_type in H.
-    fold expression_type in H.
-    destruct H1.
-    unfold expression_type in H1.
-    fold expression_type in H1.
-    force_expr (expression_type CE (NatMap.add v s TE) rec) H1.
-    destruct d.
-
-    (* Case 1: receiver has interface type. *)
-    exists es.
-    simpl in H1.
-    force_options.
-    destruct name.
-    force_options.
-    destruct f.
-    force_options.
-    destruct i.
-    force_options.
-    (* The receiver class must be the same. *)
-    assert (expression_type CE (NatMap.add v t TE) rec = [DT_Interface_Type (Interface_Type n0)]).
-    pose proof (H CE TE v s t (DT_Interface_Type (Interface_Type n0)) (conj H4 H2)) as IH_rec.
-    destruct IH_rec.
-    destruct H3.
-    destruct x.
-    destruct i0.
-    unfold_subtype H10.
-    crush.
-    unfold_subtype H10.
-    destruct f.
-    crush.
-    (* The function called must have the same type. *)
-    unfold expression_type.
-    fold expression_type.
-    rewrite H3; simpl.
-    (* The argument is still well typed. *)
-    pose proof (H0 CE TE v s t d (conj H5 H2)) as IH_arg.
-    destruct IH_arg.
-    destruct H10.
-    rewrite H10.
-    simpl.
-    intuition; crush.
-    rewrite H6.
-    assert (x ◁ d0).
-    pose proof (subtype_trans d x d0 (conj H11 H7)); crush.
-    rewrite H1; crush.
-
-    (* Case 2: The receiver has function type. *)
-    rewrite bind_some in H1.
-    force_options.
-    destruct name.
-    force_options.
-    destruct f0.
-    force_options.
-    pose proof (H CE TE v s t (DT_Function_Type f) (conj H4 H2)).
-    destruct H3.
-    destruct H3.
-    destruct x.
-    unfold_subtype H9.
-    destruct i.
-    crush.
-    destruct f; destruct f0.
-    simplify_subtypes.
-    rewrite Bool.andb_true_iff in H9; destruct H9.
-    assert (es = d3) by crush.
-    exists d5.
-    intuition; [idtac|crush].
-    unfold expression_type.
-    fold expression_type.
-    rewrite H3.
-    rewrite bind_some.
-    pose proof (H0 CE TE v s t d (conj H5 H2)).
-    destruct H12.
-    destruct H12.
-    rewrite H12.
-    rewrite bind_some.
-    rewrite H7.
-    rewrite bind_some.
-    assert (d2 = d0) by crush.
-    rewrite H11 in *; clear H11.
-    rewrite H14 in *; clear H14.
-    assert (x ◁ d0).
-    refine (subtype_trans d x d0 _); auto.
-    assert (x ◁ d4).
-    refine (subtype_trans d0 x d4 _); auto.
-    rewrite H14.
-    crush.
-  Qed.
-  Hint Immediate subtype_at_meth_invo.
-
-  Theorem subtype_homo_expr : forall e, subtype_at e.
-    Hint Extern 1 =>
-      match goal with
-        [ x : arguments |- _ ] => destruct x
-      end.
-    apply (expr_induction subtype_at); crush.
-  Qed.
-
-  Definition type_env_subtype (TE': type_env) (TE: type_env) :=
-    forall v s, NatMap.MapsTo v s TE -> exists t, NatMap.MapsTo v t TE' /\ t ◁ s.
-
-  Notation "X ◂ Y" := (type_env_subtype X Y) (at level 71, no associativity).
-
-  Lemma type_env_subtype_refl : forall TE, TE ◂ TE.
-    unfold type_env_subtype.
-    intros.
-    exists s.
-    crush.
-  Qed.
-  Hint Immediate type_env_subtype_refl.
-
-  Lemma type_env_subtype_1 :
-    forall v d d' TE TE', TE ◂ TE' -> d ◁ d' -> NatMap.add v d TE ◂ NatMap.add v d' TE'.
-    intros.
-    unfold type_env_subtype in *.
-    intros.
-    destruct (N.eq_dec v0 v).
-    rewrite e in *; clear e.
-    exists d.
-    crush.
-    assert (s = d') by
-        (rewrite NatMapFacts.add_mapsto_iff in H1; crush).
-    crush.
-
-    rewrite NatMapFacts.add_mapsto_iff in H1.
-    destruct H1; [crush|idtac].
-    destruct H1.
-    destruct (H v0 s H2).
-    exists x.
-    crush.
-  Qed.
-  Hint Resolve type_env_subtype_1.
-
-  Definition expr_extra_irrelevance_at e :=
-    forall CE TE et v t,
-      ~NatMap.In v TE ->
-      expression_type CE TE e = [et] ->
-      expression_type CE (NatMap.add v t TE) e = [et].
-
-  Theorem expr_extra_irrelvance : forall e, expr_extra_irrelevance_at e.
-    apply (expr_induction expr_extra_irrelevance_at).
-    crush.
-    crush.
-    crush.
-
-    unfold expr_extra_irrelevance_at.
-    intros.
-    simpl in *.
-    apply NatMap.find_1.
-    apply NatMap.find_2 in H0.
-    assert (v <> n).
-    contradict H.
-    unfold NatMap.MapsTo in *.
-    unfold NatMap.In in *.
-    unfold NatMap.Raw.PX.In in *.
-    exists et; crush.
-    crush.
-
-    unfold expr_extra_irrelevance_at.
-    intros.
-    simpl in H1.
-    force_options.
-    pose proof (H _ _ _ _ t H0 H3).
-    crush.
-
-    crush.
-    crush.
-
-    unfold expr_extra_irrelevance_at.
-    intros.
-    unfold expression_type in H2.
-    fold expression_type in H2.
-    remember (expression_type CE TE e) as E.
-    destruct E; [idtac|simpl in H1; contradict H1; crush].
-    pose proof (H _ _ _ _ t H1 (eq_sym HeqE)).
-    rewrite bind_some in H2.
-    destruct a.
-    force_options.
-    pose proof (H0 _ _ _ _ t H1 H5).
-    destruct n.
-    unfold expression_type.
-    fold expression_type.
-    rewrite H3.
-    rewrite H4.
-    rewrite bind_some.
-    rewrite bind_some.
-    crush.
-
-
-    unfold expr_extra_irrelevance_at.
-    crush.
-
-    crush.
-  Qed.
-
-  Theorem subtype_homo_env_expr :
-    forall e CE TE TE' es,
-                 expression_type CE TE e = [es] /\ TE' ◂ TE ->
-     (exists et, expression_type CE TE' e = [et] /\ et ◁ es).
-  Proof.
-    (* This is tedious to prove in Coq, but it follows directly from
-       subtype_homo_expr and expr_extra_irrelevance, along with the finiteness
-       of finite maps. *)
-  Admitted.
-
-  Definition subtype_at_stmt (st: statement) :=
-    forall CE X X' Y r,
-                 statement_type CE X st r = [X'] /\ Y ◂ X ->
-      exists Y', statement_type CE Y st r = [Y'] /\ Y' ◂ X'.
-
-  Local Lemma subtype_at_return : forall r, subtype_at_stmt (S_Return_Statement r).
-  Proof.
-    unfold subtype_at_stmt.
-    intros.
-    destruct r.
-    unfold statement_type in *.
-    intuition.
-    force_options.
-    inversion H0.
-    pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
-    destruct H.
-    exists Y.
-    crush.
-    assert (x ◁ r0) by (refine (subtype_trans d x r0 _); auto).
-    crush.
-  Qed.
-  Hint Immediate subtype_at_return.
-
-  Local Lemma subtype_at_vardecl : forall vd, subtype_at_stmt (S_Variable_Declaration vd).
-  Proof.
-    unfold subtype_at_stmt.
-    intros.
-    unfold statement_type in *.
-    destruct vd.
-    destruct o; [idtac|crush].
-    intuition.
-    force_options.
-    assert (forall A (x y : A), [x] = [y] -> x = y) as R by crush.
-    apply R in H0; clear R.
-    pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
-    destruct H.
-    intuition.
-    rewrite H4.
-    simpl.
-    assert (x ◁ d) by
-        (refine (subtype_trans d0 x d _); crush).
-    exists (NatMap.add n d Y).
-    crush.
-  Qed.
-  Hint Immediate subtype_at_vardecl.
-
-  Local Lemma subtype_at_exprstmt : forall es, subtype_at_stmt (S_Expression_Statement es).
-  Proof.
-    unfold subtype_at_stmt.
-    unfold statement_type in *.
-    intros.
-    destruct es.
-    intuition; force_options.
-    inversion H0; clear H0.
-    exists Y.
-    pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
-    destruct H.
-    intuition.
-    rewrite H0.
-    crush.
-    crush.
-  Qed.
-  Hint Immediate subtype_at_exprstmt.
-
-  Local Lemma subtype_at_block : forall ss, Forall subtype_at_stmt ss -> subtype_at_stmt (S_Block (Block ss)).
-  Proof.
-    induction ss.
-
-    unfold subtype_at_stmt.
-    intros.
-    simpl.
-    exists Y.
-    crush.
-
-    intros.
-    rewrite forall_list_all in H.
-    simpl in H.
-    destruct H.
-    unfold subtype_at_stmt.
-    intros.
-    unfold statement_type in *.
-    fold statement_type in *.
-    unfold subtype_at_stmt in H.
-    extract_head statement_type in H1.
-    destruct H2; [idtac|simpl in H1; crush].
-    simpl in H1.
-    destruct H1.
-    pose proof (H _ _ _ _ _ (conj (eq_sym H2Eq) H2)) as Z.
-    destruct Z.
-    destruct H3.
-    intuition.
-    simpl.
-    match type of H1 with
-    | ?Y _ _ = ?W => remember Y as PS
-    end.
-
-    (* We need to prove a lemma about the inline helper function. *)
-    assert (
-        forall X Y Y',
-          X ◂ Y -> PS Y ss = [Y'] ->
-          exists X', PS X ss = [X'] /\ X' ◂ Y') as L.
-    generalize H0.
-    generalize ss as l.
-    clear - HeqPS.
-    induction l.
-    intros.
-    exists X; crush.
-
-    intros.
-    destruct H0.
-    rewrite HeqPS in H1.
-    rewrite <- HeqPS in H1.
-    force_options.
-    rewrite HeqPS.
-    rewrite <- HeqPS.
-    pose proof (H0 _ _ _ _ _ (conj H4 H)).
-    destruct H3; destruct H3.
-    rewrite H3; simpl.
-    apply (IHl H2 x t); crush.
-
-    clear HeqPS.
-    clear H.
-    rewrite H3.
-    simpl.
-    pose proof (L x t X' H4 H1).
-    destruct H as (Y', H).
-    destruct H.
-    exists Y'.
-    crush.
-  Qed.
-  Hint Immediate subtype_at_block.
-
-  Theorem subtype_homo_stmt : forall s, subtype_at_stmt s.
-  Proof.
-    apply (statement_induction subtype_at_stmt); auto.
-  Qed.
-
-End Typing_Equivalence_Homomorphism.
-
-Section Environments.
-
-(** Function environment maps defined functions to their procedure type. Used
-    for direct method invocation, direct property get etc. *)
-Definition member_env : Type := NatMap.t member.
-
-Definition procedure_dissect (envs: class_env * member_env) (p : procedure) :=
-  let (CE, ME)             := envs in
-  let (memb, _, fn)        := p in
-  let (nn, name)           := memb in
-  let (name_str)           := name in
-  let (ref)                := nn in
-  let (id)                 := ref in
-  let (param, ret_type, _) := fn in
-  let (_, param_type, _)   := param in
-  let proc := mk_procedure_desc name_str id (Function_Type param_type ret_type) in
-  (proc, (CE, NatMap.add id (M_Procedure p) ME)).
-
-Definition procedure_to_env p envs := snd (procedure_dissect envs p).
-Definition procedure_to_desc envs p := fst (procedure_dissect envs p).
-
-Definition class_to_env (c : class) (envs: class_env * member_env) :=
-  let (nn, name, procs) := c in
-  let (ref)             := nn in
-  let (id)              := ref in
-  let envs'             := List.fold_right procedure_to_env envs procs in
-  let procedures        := List.map (procedure_to_desc envs') procs in
-  let getters           := List.map (fun P => mk_getter_desc (pr_name P) (pr_ref P) (DT_Function_Type (pr_type P))) procedures in
-  let (CE, ME)          := envs' in
-  (NatMap.add id (mk_interface procedures getters) CE, ME).
-
-Definition lib_to_env (l: library) : class_env * member_env :=
-  let (_, classes, top_procs) := l in
-  let envs := List.fold_right class_to_env (NatMap.empty _, NatMap.empty _) classes in
-  List.fold_right procedure_to_env envs top_procs.
-
-Local Ltac destruct_types :=
-  repeat match goal with
-         | [H : interface_type       |- _] => destruct H
-         | [H : function_type        |- _] => destruct H
-         | [H : procedure            |- _] => destruct H
-         | [H : member_data          |- _] => destruct H
-         | [H : named_node_data      |- _] => destruct H
-         | [H : function_node        |- _] => destruct H
-         | [H : procedure_desc       |- _] => destruct H
-         | [H : getter_desc          |- _] => destruct H
-         | [H : name                 |- _] => destruct H
-         | [H : reference            |- _] => destruct H
-         | [H : variable_declaration |- _] => destruct H
-         | [H : class                |- _] => destruct H
-         end.
-
-Local Lemma proc_desc_noenv : forall env env', procedure_to_desc env = procedure_to_desc env'.
-Proof.
-  intros.
-  apply functional_extensionality.
-  intros.
-  unfold procedure_to_desc.
-  unfold procedure_dissect.
-  destruct env; destruct env'.
-  destruct_types.
-  crush.
-Qed.
-
-Local Definition mono
-    (envs: class_env * member_env)
-    (envs': class_env * member_env) : Prop :=
-  let (CE, ME) := envs in
-  let (CE', ME') := envs' in
-  (forall n, NatMap.In n CE -> NatMap.In n CE') /\
-  (forall n, NatMap.In n ME -> NatMap.In n ME').
-
-Local Lemma mono_trans : forall x y z, mono x y -> mono y z -> mono x z.
-Proof.
-  intros.
-  destruct x; destruct y; destruct z.
-  unfold mono in *.
-  crush.
-Qed.
-
-Local Lemma mono_sym : forall x, mono x x.
-Proof.
-  crush.
-Qed.
-
-Hint Rewrite add_in_iff.
-Local Lemma proc_mono :
-  forall E1 E2 p p',
-    procedure_dissect E1 p = (p', E2) -> mono E1 E2.
-Proof.
-  intros.
-  unfold procedure_dissect in H.
-  destruct_types.
-  destruct E1; destruct E2.
-  unfold mono.
-  inject H.
-  crush.
-Qed.
-Hint Resolve proc_mono.
-
-Local Lemma class_mono :
-  forall E1 E2 c, class_to_env c E1 = E2 -> mono E1 E2.
-Proof.
-  intros.
-  destruct E1; destruct E2.
-  unfold class_to_env in H.
-  destruct_types.
-  extract_head fold_right in H.
-  assert (mono (c0, m) H0).
-  pose proof (foldr_mono mono l (c0, m) procedure_to_env mono_sym mono_trans) as X.
-  continue_with X.
-  intros.
-  unfold procedure_to_env.
-  remember (procedure_dissect a b) as P.
-  destruct P.
-  simpl.
-  apply (proc_mono _ _ _ _ (eq_sym HeqP)).
-  crush.
-
-  destruct H0.
-  assert (mono (c, m) (t, m0)) by
-    (inversion H;
-     unfold mono;
-     crush); crush.
-Qed.
-
-Local Lemma fold_proc_invar :
-  forall E1 E2 ps,
-    List.fold_right procedure_to_env E1 ps = E2 ->
-    fst E1 = fst E2.
-Proof.
-  intros.
-  destruct E1 as (CE, ME); destruct E2 as (CE' , ME').
-  pose (x := @foldr_preserve (class_env * member_env) procedure (fun env => let (CE', _) := env in CE = CE') ps (CE, ME) procedure_to_env).
-  continue_with x.
-  crush.
-  destruct_types.
-  crush.
-  continue_with x.
-  crush.
-  continue_with x3; crush.
-  rewrite H in H3.
-  assumption.
-Qed.
-
-Local Lemma class_env_invar :
-  forall CE ME CE' ME' id id' intf n ps,
-    id <> id' ->
-    class_to_env (Class (Named_Node (Reference id')) n ps) (CE, ME) = (CE', ME') ->
-    (NatMap.MapsTo id intf CE' -> NatMap.MapsTo id intf CE).
-Proof.
-  unfold class_to_env.
-  intros.
-  extract_head fold_right in H0 as F.
-  destruct F as (CE_f, ME_f).
-  inversion H0; clear H0.
-  rewrite H4 in *; clear H4.
-  assert (NatMap.MapsTo id intf CE_f).
-  rewrite <- H3 in H1.
-  apply (NatMap.add_3 (not_eq_sym H) H1).
-  apply eq_sym in FEq.
-  apply fold_proc_invar in FEq.
-  simpl in FEq.
-  crush.
-Qed.
-
-Hint Resolve NatMap.add_1.
-Local Lemma program_wf': forall cs CE ME class_id intf proc_desc,
-     List.fold_right class_to_env (NatMap.empty _, NatMap.empty _) cs = (CE, ME)
-  -> NatMap.MapsTo class_id intf CE
-  -> List.In proc_desc (procedures intf)
-  -> NatMap.In (pr_ref proc_desc) ME.
-Proof.
-  intro cs.
-  induction cs.
-
-  (* Base case: no classes in the library. Contradiction. *)
-  intros.
-  unfold fold_right in H.
-  inversion H.
-  contradict H0.
-  pose proof (@NatMap.empty_1 interface).
-  rewrite <- H3 in *.
-  clear H3; clear CE.
-  unfold NatMap.Empty in *.
-  unfold NatMap.empty in H0.
-  unfold NatMap.empty.
-  unfold NatMap.MapsTo.
-  simpl in *.
-  unfold NatMap.Raw.Empty in H0.
-  generalize class_id intf.
-  assumption.
-
-  (* Inductive case: consider whether top class is ours or not. *)
-  intros.
-  simpl in *.
-  destruct a; destruct n; destruct r.
-  destruct (N.eq_dec n class_id).
-
-  (* Case 1.1: head class is different. *)
-  Focus 2.
-  extract_head fold_right in H as Fold.
-  destruct Fold as (CE_f, ME_f).
-
-  (* class_id must map to the same interface after applying the previous classes. *)
-  assert (NatMap.MapsTo class_id intf CE_f).
-  pose proof (class_env_invar CE_f ME_f CE ME class_id n intf s l (not_eq_sym n0)) as H2.
-  continue_with H2; crush.
-
-  (* Apply the induction hypothesis. *)
-  pose proof (IHcs CE_f ME_f class_id intf proc_desc eq_refl H2 H1) as IH.
-  assert (mono (CE_f, ME_f) (CE, ME)).
-  apply (class_mono _ _ ((Class (Named_Node (Reference n)) s l))); crush.
-  crush.
-
-  (* Case 1.2: head class is the same. *)
-  extract_head fold_right in H as Fold.
-  unfold class_to_env in H.
-  extract_head fold_right in H as FoldP.
-  destruct FoldP as (CE_f, ME_f).
-  inversion H; clear H.
-  rewrite H4 in *; clear H4.
-  rewrite e in *; clear e.
-  extract_head mk_interface in H3 as I, IEq.
-  assert (NatMap.MapsTo class_id I CE) by crush.
-  pose proof (@MoreNatMapFacts.add_3 _ CE class_id intf I (conj H0 H)).
-  rewrite H2 in *; clear H2.
-  clear H0.
-  clear H.
-  simpl in H1.
-  clear IHcs.
-  rewrite IEq in *.
-  clear IEq.
-  clear I.
-  generalize H1.
-  generalize FoldPEq.
-  generalize CE_f ME.
-  clear H1.
-  clear FoldPEq.
-  clear H3.
-  induction l.
-  intros.
-  unfold In in H1.
-  simpl in H1.
-  crush.
-  intros.
-  destruct a; destruct n0; destruct r.
-  destruct proc_desc.
-  simpl.
-  simpl in H1.
-  destruct H1.
-  unfold procedure_to_desc in H.
-  unfold procedure_dissect in H.
-  destruct_types.
-  simpl in H.
-  inversion H.
-  rewrite H1 in *; clear H1.
-  rewrite H2 in *; clear H2.
-  rewrite H3 in *; clear H3.
-  rewrite H4 in *; clear H4.
-  clear H.
-  simpl in FoldPEq.
-  extract_head (fold_right procedure_to_env) in FoldPEq as Rest.
-  destruct Rest.
-  unfold procedure_to_env in FoldPEq.
-  unfold procedure_dissect in FoldPEq.
-  simpl in FoldPEq.
-  inject FoldPEq.
-  crush.
-
-  simpl in FoldPEq.
-  simpl in IHl.
-  extract_head fold_right in FoldPEq as InnerFold.
-  destruct InnerFold as (CE_i, ME_i).
-  unfold procedure_to_env in FoldPEq.
-  unfold procedure_dissect in FoldPEq.
-  destruct_types.
-  simpl in FoldPEq.
-  rewrite (proc_desc_noenv (CE_f0, ME0) (CE_i, ME_i)) in H.
-  pose proof (IHl CE_i ME_i eq_refl H).
-  inversion FoldPEq.
-  clear FoldPEq.
-  clear H2.
-  crush.
-Qed.
-
-Lemma program_wf: forall l CE ME class_id intf proc_desc,
-     lib_to_env l = (CE, ME)
-  -> NatMap.MapsTo class_id intf CE
-  -> List.In proc_desc (procedures intf)
-  -> NatMap.In (pr_ref proc_desc) ME.
-Proof.
-  intros.
-  destruct l.
-  unfold lib_to_env in *.
-  extract_head (fold_right class_to_env) in H as Inner.
-  destruct Inner as (CE_i, ME_i).
-  assert (NatMap.MapsTo class_id intf CE_i).
-
-  apply eq_sym in InnerEq.
-  apply (fold_proc_invar _ _ _) in H.
-  simpl in H.
-  crush.
-
-  pose proof (program_wf' l CE_i ME_i class_id intf proc_desc (eq_sym InnerEq) H2 H1).
-  assert (mono (CE_i, ME_i) (CE, ME)).
-  rewrite <- H.
-  apply foldr_mono.
-  exact mono_sym.
-  exact mono_trans.
-  intros.
-  unfold procedure_to_env in *.
-  remember (procedure_dissect a b) as Z.
-  destruct Z.
-  simpl.
-  apply (proc_mono a p0 b p).
-  auto.
-  unfold mono in H4.
-  crush.
-Qed.
-
-End Environments.
diff --git a/pkg/kernel/coq/OperationalSemantics.v b/pkg/kernel/coq/OperationalSemantics.v
deleted file mode 100644
index 99a923e..0000000
--- a/pkg/kernel/coq/OperationalSemantics.v
+++ /dev/null
@@ -1,1385 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file. *)
-
-
-Require Import Coq.Lists.List.
-Require Import Common.
-Require Import Syntax.
-Require Import ObjectModel.
-
-
-Import ObjectModel.Subtyping.
-
-Notation "s <: t" := (subtype (s, t) = true) (at level 70, no associativity).
-
-
-Section OperationalSemantics.
-
-
-(** The well-formedness hypothesis is that the environments are built via
-  [lib_to_env] function from the object model module.  [program_wf] theorem
-  defined there provides the rest of the well-formedness properties.  In
-  [OperationalSemantics] sections we don't need the hypothesis itself, just the
-  environments. *)
-Variable CE : class_env.
-Variable ME : member_env.
-
-
-(** [runtime_value] represents the runtime values used in the abstract machine
-  during program execution.  The values are typed and have some relation to
-  syntactic types and internal representation of their interfaces. Currently a
-  runtime value doesn't have a state, it only has a type.  It should have a
-  state when a broader subset of Kernel is formalized. *)
-Record runtime_value := mk_runtime_value {
-
-  (** Null is currently modelled using None as the value of [runtime_type].
-    It may change in future once [dart_type] includes a constructor for Null
-    or Bottom.  Also, in the current subset of Kernel type Null can't be
-    expressed syntactically; therefore, it can't be a declared type of a method
-    parameter, a declared type of a variable, etc.  The only use of Null in the
-    current subset of Kernel is that of a runtime type of a runtime value.  In
-    that case the declared type of the variable holding such value and the
-    runtime type of the value do not match.  *)
-  runtime_type : option dart_type;
-}.
-
-
-(** [value_of_type] defines the meaning of statement "the runtime value has the
-  given interface and the given type". *)
-Inductive value_of_type :
-    runtime_value -> interface -> option dart_type -> Prop :=
-
-  (** If the type of the runtime value is an interface type, then the
-    corresponding interface should be in the global class environment. *)
-  | RFS_Interface_Type :
-    forall val intf type class_id,
-    type = DT_Interface_Type (Interface_Type class_id) ->
-    NatMap.find class_id CE = Some intf ->
-    (runtime_type val) = Some type ->
-    value_of_type val intf (Some type)
-
-  (** If the type of the runtime value is a function type, then the
-    corresponding interface may or may not be in the global class environment,
-    but should have a particular shape. *)
-  | RFS_Function_Type :
-    forall val intf ftype memb_id proc,
-    (procedures intf) = (mk_procedure_desc "call" memb_id ftype) :: nil ->
-    (getters intf) =
-      (mk_getter_desc "call" memb_id (DT_Function_Type ftype)) :: nil ->
-    NatMap.MapsTo memb_id (M_Procedure proc) ME ->
-    (runtime_type val) = Some (DT_Function_Type ftype) ->
-    value_of_type val intf (Some (DT_Function_Type ftype))
-
-  (** Null values are currently represented as runtime values that have [None]
-    in place of their type.  In future, for example when the Bottom type or
-    explicit Null type are added to the syntax of dart types, the
-    representation may change. *)
-  | RFS_Null_Type :
-    forall val intf,
-    (procedures intf) = nil ->
-    (getters intf) = nil ->
-    (runtime_type val) = None ->
-    value_of_type val intf None.
-
-
-(** Describes that the given dart type has a method with the given name.  The
-  predicate can be applied to runtime types of values, so it should accept None
-  as the first parameter to account for `null` values.
-
-  Currently, values of function type only have "call" methods, and null doesn't
-  have any methods. *)
-Inductive method_exists : option dart_type -> string -> Prop :=
-
-  | ME_Interface_Type :
-    forall name intf desc class_id type,
-    type = (DT_Interface_Type (Interface_Type class_id)) ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
-    List.In desc (procedures intf) ->
-    ((pr_name desc) = name)%string ->
-    method_exists (Some type) name
-
-  | ME_Function_Type :
-    forall type intf desc ftype,
-    type = (DT_Function_Type ftype) ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
-    List.In desc (procedures intf) ->
-    ((pr_name desc) = "call")%string ->
-    method_exists (Some type) "call".
-
-
-(** Describes that the method with the given name of the given dart type
-  accepts arguments of the given type.  The predicate can be applied to runtime
-  types of values, so it should accept None as the first parameter to account
-  for `null` values.
-
-  Currently, values of function type only have "call" methods, and null doesn't
-  have any methods. *)
-Inductive method_accepts :
-    option dart_type -> string -> option dart_type -> Prop :=
-
-  | MA_Non_Null :
-    forall name intf desc rcvr_type arg_type par_type ret_type,
-    method_exists (Some rcvr_type) name ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
-    List.In desc (procedures intf) ->
-    ((pr_name desc) = name)%string ->
-    (pr_type desc) = Function_Type par_type ret_type ->
-    arg_type <: par_type ->
-    method_accepts (Some rcvr_type) name (Some arg_type)
-
-  | MA_Null :
-    forall rcvr_type_opt name,
-    method_exists rcvr_type_opt name ->
-    method_accepts rcvr_type_opt name None.
-
-
-(** Describes that the method with the given name of the given dart type
-  returns a value of the given type.  The predicate can be applied to runtime
-  types of values, so it should accept None as the first parameter to account
-  for `null` values.
-
-  Currently, values of function type only have "call" methods, and null doesn't
-  have any methods. *)
-Inductive method_returns :
-    option dart_type -> string -> dart_type -> Prop :=
-
-  | Method_Returns :
-    forall name intf desc rcvr_type par_type ret_type,
-    method_exists (Some rcvr_type) name ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
-    List.In desc (procedures intf) ->
-    ((pr_name desc) = name)%string ->
-    (pr_type desc) = Function_Type par_type ret_type ->
-    method_returns (Some rcvr_type) name ret_type.
-
-
-(** Describes that the given dart type has a getter with the given name.  The
-  predicate can be applied to runtime types of values, so it should accept None
-  as the first parameter to account for `null` values.
-
-  Currently, values of function type only have "call" getters, and null doesn't
-  have any getters. *)
-Inductive getter_exists : option dart_type -> string -> Prop :=
-
-  | GE_Interface_Type :
-    forall name intf desc class_id type,
-    type = (DT_Interface_Type (Interface_Type class_id)) ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
-    List.In desc (getters intf) ->
-    ((gt_name desc) = name)%string ->
-    getter_exists (Some type) name
-
-  | GE_Function_Type :
-    forall type intf desc ftype,
-    type = (DT_Function_Type ftype) ->
-    (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-      together the interface and the type, avoiding the construction of the
-      value. *)
-    value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
-    List.In desc (getters intf) ->
-    ((gt_name desc) = "call")%string ->
-    getter_exists (Some type) "call".
-
-
-(** Describes that the getter with the given name of the given dart type
-  returns a value of the given type.  The predicate can be applied to runtime
-  types of values, so it should accept None as the first parameter to account
-  for `null` values.
-
-  Currently, values of function type only have "call" getters, and null doesn't
-  have any getters. *)
-Inductive getter_returns :
-    option dart_type -> string -> dart_type -> Prop :=
-
-  | Getter_Returns :
-    forall name intf desc rcvr_type,
-    getter_exists (Some rcvr_type) name ->
-    value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
-    List.In desc (getters intf) ->
-    ((gt_name desc) = name)%string ->
-    getter_returns (Some rcvr_type) name (gt_type desc).
-
-
-(** The environment that is used by the abstract machine to map the currently
-  visible set of variables to their types and runtime values is represented as
-  a list of records.
-
-  [var_type] represents the declared type of the variable and may not match
-  the runtime type of the [value] in case the latter is Null.  This is because
-  in the current subset of Kernel Null can't be represented syntactically. *)
-Record env_entry := mk_env_entry {
-  var_ref   : nat;
-  var_type  : dart_type;
-  value     : runtime_value;
-}.
-
-Definition environment := list env_entry.
-
-Definition env_get
-      (var : nat)
-      (env : environment)
-    : option env_entry :=
-  List.find (fun entry => Nat.eqb var (var_ref entry)) env.
-
-Definition env_extend
-      (var  : nat)
-      (type : dart_type)
-      (val  : runtime_value)
-      (env  : environment)
-    : environment :=
-  (mk_env_entry var type val) :: env.
-
-Definition env_in
-      (var : nat)
-      (env : environment)
-    : Prop :=
-  match List.find (fun entry => Nat.eqb var (var_ref entry)) env with
-  | None    => False
-  | Some _  => True
-  end.
-
-Definition empty_env : environment := nil.
-
-Definition env_to_type_env : environment -> type_env :=
-  fun env => List.fold_left
-    (fun TE entry => NatMap.add (var_ref entry) (var_type entry) TE)
-    env
-    (NatMap.empty dart_type).
-
-
-(** TODO(dmitryas): Write descriptive comments.
-
-  First, [untyped_expression_continuation] is defined.  Its only difference
-  from [expression_continuation] is that the value expected by the continuation
-  is untyped; [expression_continuation] pairs an
-  [untyped_expression_continuation] and a [dart_type], giving the expected
-  value a type.  It is done to simplify the extraction of the type from an
-  expression continuation in predicates. *)
-Inductive untyped_expression_continuation : Set :=
-
-  (** The constructor receives the following parameters:
-
-    - an [environment]
-    - a [expression_continuation]
-    - a [statement_continuation] *)
-  | Expression_Ek :
-       environment
-    -> expression_continuation
-    -> statement_continuation
-    -> untyped_expression_continuation
-
-  (** The constructor receives the following parameters:
-
-    - a [string]
-    - an [expression]
-    - an [environment]
-    - a [expression_continuation] *)
-  | Method_Invocation_Ek :
-       string
-    -> expression
-    -> environment
-    -> expression_continuation
-    -> untyped_expression_continuation
-
-  (** The constructor receives the following parameters:
-
-    - a [runtime_value]
-    - a [string]
-    - an [environment]
-    - a [expression_continuation] *)
-  | Invocation_Ek :
-       runtime_value
-    -> string
-    -> environment
-    -> expression_continuation
-    -> untyped_expression_continuation
-
-  (** The constructor receives the following parameters:
-
-    - a [string]
-    - a [expression_continuation] *)
-  | Property_Get_Ek :
-       string
-    -> expression_continuation
-    -> untyped_expression_continuation
-
-  (** The constructor receives the following parameters:
-
-    - a [nat]
-    - a [dart_type]
-    - an [environment]
-    - a [statement_continuation] *)
-  | Var_Declaration_Ek :
-       nat
-    -> dart_type
-    -> environment
-    -> statement_continuation
-    -> untyped_expression_continuation
-
-  (** [Halt_Ek] represents the end of program execution.  The main procedure
-    returns a value (or null) to this expression continuation.  The value is
-    then ignored, and the program execution halts.  The constructor doesn't
-    receive any parameters. *)
-  | Halt_Ek :
-    untyped_expression_continuation
-
-(** TODO(dmitryas): Write descriptive comments. *)
-with statement_continuation : Set :=
-
-  (** The constructor receives the following parameters:
-
-    - a [expression_continuation]
-    - a [runtime_value] *)
-  | Exit_Sk :
-       expression_continuation
-    -> runtime_value
-    -> statement_continuation
-
-  (** The constructor receives the following parameters:
-
-    - a list of [statement]s
-    - an [environment]
-    - a [expression_continuation]
-    - a [statement_continuation] *)
-  | Block_Sk :
-       list statement
-    -> environment
-    -> expression_continuation
-    -> statement_continuation
-    -> statement_continuation
-
-(** A [expression_continuation] encapsulates a [dart_type] that signifies
-  the type of the value expected by the expression continuation as the
-  input.
-
-  In the current subset of Kernel the Null type can't be described
-  syntactically, so it can't be a type of a typed expression or statement.
-  Therefore, the type of the value expected by the expression continuation
-  can't be Null, and it's expressed as [dart_type], not [option dart_type]. *)
-with expression_continuation : Set :=
-
-  | Expression_Continuation :
-       untyped_expression_continuation
-    -> dart_type
-    -> expression_continuation.
-
-
-(** [configuration] represents configurations of the CESK abstract machine that
-  is used for defining the operational semantics.  A transition of the machine
-  represents a small step of the small-step operational semantics.  There are
-  the following types of configurations:
-
-  - [Eval_Configuration] — encapsulates a syntactic expression and an
-    expression continuation.  After evaluation of the expression the resulting
-    value is passed to the expression configuration.
-  - [Exec_Configuration] — encapsulates a syntactic statement.  Represents the
-    execution of the statement.
-  - [Value_Passing_Configuration] — encapsulates a value and an expression
-    continuation.  The value is passed to the expression continuation.
-  - [Forward_Configuration] — encapsulates a statement continuation.
-    The execution of the program proceeds to the associated statement. *)
-Inductive configuration : Set :=
-
-  (** [Eval_Configuration] represents the beginning of an expression
-    evaluation.  The constructor receives the following parameters:
-
-    - an [expression] — the expression to be evaluated;
-    - an [environment] — the mapping from variables to values that is to be
-      used during the expression evaluation;
-    - a [expression_continuation] — the continuation that will receive
-      the value of the expression after its evaluation. *)
-  | Eval_Configuration :
-       expression
-    -> environment
-    -> expression_continuation
-    -> configuration
-
-  (** [Exec_Configuration] represents the beginning of a statement execution.
-    The constructor receives the following parameters:
-
-    - a [statement] — the statement to be executed;
-    - an [environment] — the mapping from variables to values that is to be
-      used during the statement execution;
-    - a [expression_continuation] — in case the executed statement
-      returns a value, this continuation will receive this value;
-    - a [statement_continuation] — in case the executed statement
-      doesn't return a value, this continuation represents the rest of the
-      program execution. *)
-  | Exec_Configuration :
-       statement
-    -> environment
-    -> expression_continuation
-    -> statement_continuation
-    -> configuration
-
-  (** [Value_Passing_Configuration] represents the end of an expression
-    evaluation.  The constructor receives the following parameters:
-
-    - a [expression_continuation] — the continuation that receives the
-      value which is the result of the expression evaluation;
-    - a [value] — the result of the expression evaluation. *)
-  | Value_Passing_Configuration :
-       expression_continuation
-    -> runtime_value
-    -> configuration
-
-  (** [Forward_Configuration] represents the rest of the program execution.
-    The constructor receives the following parameters:
-
-    - a [statement_continuation] — represents the rest of the program
-      execution;
-    - an [environment] — the mapping from variables to values that is to be
-      used during the execution of the rest of the program. *)
-  | Forward_Configuration :
-       statement_continuation
-    -> environment
-    -> configuration.
-
-
-(** Represents steps (a.k.a. transitions) of the abstract machine. *)
-Inductive step : configuration -> configuration -> Prop :=
-
-  (** <Block(stmt :: stmts), ρ, κE, κS>exec ==>
-        <stmt, ρ, κE, BlockSK(stmts, ρ, κE, κS)>exec *)
-  | Exec_Block :
-    forall stmt stmts env ret_cont next_cont,
-    step (Exec_Configuration
-            (S_Block (Block (stmt :: stmts)))
-            env ret_cont next_cont)
-         (Exec_Configuration
-            stmt env ret_cont
-            (Block_Sk stmts env ret_cont next_cont))
-
-  (** <Block(#[]#), ρ, κE, κS>exec ==> <κS, ρ>forward *)
-  | Exec_Block_Empty :
-    forall env ret_cont next_cont,
-    step (Exec_Configuration
-            (S_Block (Block nil)) env ret_cont next_cont)
-         (Forward_Configuration next_cont env)
-
-  (** <BlockSK(stmt :: stmts, ρ, κE, κS), ρ'>forward ==>
-        <stmt, ρ', κE, BlockSK(stmts, ρ, κE, κS)>exec *)
-  | Forward_Block_Sk :
-    forall stmt stmts env ret_cont next_cont env',
-    step (Forward_Configuration
-            (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-            env')
-         (Exec_Configuration
-            stmt env' ret_cont
-            (Block_Sk stmts env ret_cont next_cont))
-
-  (** <BlockSK(#[]#, ρ, κE, κS), ρ'>forward ==> <κS, ρ>forward *)
-  | Forward_Block_Sk_Empty :
-    forall env ret_cont next_cont env',
-    step (Forward_Configuration
-            (Block_Sk nil env ret_cont next_cont)
-            env')
-         (Forward_Configuration next_cont env)
-
-  (** <ExpressionStatement(expr), ρ, κE, κS>exec ==>
-        <expr, ρ, ExpressionEK(ρ, κE, κS)>eval *)
-  | Exec_Expression_Statement :
-    forall expr env ret_cont next_cont ret_type,
-    expression_type CE (env_to_type_env env) expr = Some ret_type ->
-    step (Exec_Configuration
-            (S_Expression_Statement (Expression_Statement expr))
-            env ret_cont next_cont)
-         (Eval_Configuration
-            expr env
-            (Expression_Continuation
-              (Expression_Ek env ret_cont next_cont)
-              ret_type))
-
-  (** <ReturnStatement(expr), ρ, κE, κS>exec ==> <expr, ρ, κE>eval *)
-  | Exec_Return_Statement :
-    forall expr env ret_cont next_cont,
-    step (Exec_Configuration
-            (S_Return_Statement (Return_Statement expr))
-             env ret_cont next_cont)
-         (Eval_Configuration expr env ret_cont)
-
-  (** <VariableGet(var), ρ, κE>eval ==> <κE, ρ(var)>pass *)
-  | Eval_Variable_Get :
-    forall var_id env ret_cont entry,
-    env_get var_id env = Some entry ->
-    step (Eval_Configuration
-            (E_Variable_Get (Variable_Get var_id)) env ret_cont)
-         (Value_Passing_Configuration
-            ret_cont (value entry))
-
-  (** <MethodInvocation(rcvr, name, arg), ρ, κE>eval ==>
-        <rcvr, ρ, MethodInvocationEK(name, arg, ρ, κE)>eval *)
-  | Eval_Method_Invocation :
-    (* TODO(dmitryas): Remove [ref] after interfaceTargetReference is removed
-      from constructor [Method_Invocation]. *)
-    forall rcvr_expr rcvr_type name arg env ret_cont ref,
-    expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
-    step (Eval_Configuration
-            (E_Invocation_Expression (IE_Method_Invocation
-              (Method_Invocation rcvr_expr (Name name) (Arguments arg) ref)))
-            env ret_cont)
-         (Eval_Configuration rcvr_expr env
-            (Expression_Continuation
-              (Method_Invocation_Ek name arg env ret_cont)
-              rcvr_type))
-
-  (** <MethodInvocationEK(name, arg, ρ, κE), rcvrVal)pass ==>
-        <arg, ρ, InvocationEK(rcvrVal, name, ρ, κE)>eval,
-      rcvrVall != null *)
-  | Pass_Method_Invocation_Ek_Non_Null :
-    forall name arg_expr arg_type env ret_cont
-        rcvr_val rcvr_type expected_rcvr_type,
-    runtime_type rcvr_val = Some rcvr_type ->
-    expression_type CE (env_to_type_env env) arg_expr = Some arg_type ->
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Method_Invocation_Ek name arg_expr env ret_cont)
-              expected_rcvr_type)
-            rcvr_val)
-         (Eval_Configuration arg_expr env
-            (Expression_Continuation
-              (Invocation_Ek rcvr_val name env ret_cont)
-              arg_type))
-
-  (** <InvocationEK(rcvrVal, name, ρ, κE), argVal>pass ==>
-        <block, ρ', κE, κS>exec,
-      where ρ' = ρ0#[#this = rcvrVal#][#arg(f) = argVal#]#,
-        block = body(f),
-        κS = ExitSK(κE, nullVal),
-        f = methods(class(rcvrVal))(name),
-        ρ0 — empty environment *)
-  | Pass_Invocation_Ek :
-    forall rcvr_val rcvr_intf rcvr_type_opt
-      proc_desc memb_data named_data func_node
-      var_id var_type var_init ret_type body
-      name arg_val arg_type env env'
-      ret_cont next_cont null_val,
-    (* TODO(dmitryas): Add the mapping: this -> rcvr_val to env'. *)
-    value_of_type rcvr_val rcvr_intf rcvr_type_opt ->
-    List.In proc_desc (procedures rcvr_intf) ->
-    NatMap.MapsTo
-      (pr_ref proc_desc)
-      (M_Procedure (Procedure memb_data named_data func_node))
-      ME ->
-    func_node =
-      Function_Node
-        (Variable_Declaration var_id var_type var_init)
-        ret_type
-        body ->
-    env' = env_extend var_id var_type arg_val empty_env ->
-    next_cont = Exit_Sk ret_cont null_val ->
-    value_of_type null_val (mk_interface nil nil) None ->
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Invocation_Ek rcvr_val name env ret_cont)
-              arg_type)
-            arg_val)
-         (Exec_Configuration body env' ret_cont next_cont)
-
-  (** <PropertyGet(rcvr, name), ρ, κE>eval ==>
-        <rcvr, ρ, PropertyGetEK(name, κE)>eval *)
-  | Eval_Property_Get :
-    forall rcvr_expr rcvr_type name env ret_cont,
-    expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
-    step (Eval_Configuration
-            (E_Property_Get (Property_Get rcvr_expr (Name name)))
-            env ret_cont)
-         (Eval_Configuration
-            rcvr_expr env
-            (Expression_Continuation
-              (Property_Get_Ek name ret_cont)
-              rcvr_type))
-
-  (** <PropertyGetEK(name, κE), rcvrVal)pass ==> <κE, f>pass,
-      where f = methods(class(rcvrVal))(name) *)
-  | Pass_Property_Get_Ek :
-    forall rcvr_val rcvr_intf rcvr_type_opt expected_rcvr_type
-        name memb_id ret_type
-        ret_val ret_intf
-        ret_cont,
-    value_of_type rcvr_val rcvr_intf rcvr_type_opt ->
-    List.In (mk_getter_desc name memb_id ret_type) (getters rcvr_intf) ->
-    value_of_type ret_val ret_intf (Some ret_type) ->
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Property_Get_Ek name ret_cont)
-              expected_rcvr_type)
-            rcvr_val)
-         (Value_Passing_Configuration
-            ret_cont ret_val)
-
-  (** <ExitSK(κE, val), ρ>forward ==> <κE, val>pass *)
-  | Forward_Exit_Sk :
-    forall ret_cont val env,
-    step (Forward_Configuration (Exit_Sk ret_cont val) env)
-         (Value_Passing_Configuration ret_cont val)
-
-  (** <ConstructorInvocation(cls), ρ, κE>eval ==> <κE, newVal>pass,
-      where newVal = new runtime value of syntactic type cls *)
-  | Eval_Constructor_Invocation :
-    forall env ret_cont new_val intf type_opt class_id,
-    NatMap.MapsTo class_id intf CE ->
-    value_of_type new_val intf type_opt ->
-    step (Eval_Configuration
-            (E_Invocation_Expression (IE_Constructor_Invocation
-              (Constructor_Invocation class_id)))
-            env ret_cont)
-         (Value_Passing_Configuration ret_cont new_val)
-
-  (** <VariableDeclaration(var, type, NONE), ρ, κE, κS>exec ==>
-        <κS, ρ'>forward,
-      where ρ' = ρ#[#var = nullVal#]# *)
-  | Exec_Variable_Declaration_Non_Init :
-    forall var type env ret_cont next_cont null_val env',
-    value_of_type null_val (mk_interface nil nil) None ->
-    env' = env_extend var type null_val env ->
-    step (Exec_Configuration
-            (S_Variable_Declaration (Variable_Declaration var type None))
-            env ret_cont next_cont)
-         (Forward_Configuration next_cont env')
-
-  (** <VariableDeclaration(var, type, expr), ρ, κE, κS>exec ==>
-        <expr, ρ, VarDeclarationEK(var, ρ, κS)>eval *)
-  | Exec_Variable_Declaration_Init :
-    forall var var_type init_type expr env ret_cont next_cont,
-    expression_type CE (env_to_type_env env) expr = Some init_type ->
-    step (Exec_Configuration
-            (S_Variable_Declaration
-              (Variable_Declaration var var_type (Some expr)))
-            env ret_cont next_cont)
-         (Eval_Configuration expr env
-            (Expression_Continuation
-              (Var_Declaration_Ek var var_type env next_cont)
-              init_type))
-
-  (** <VarDeclarationEK(var, ρ, κS), val>pass ==> <κS, ρ'>forward,
-      where ρ' = ρ#[#var = val#]# *)
-  | Pass_Var_Declaration_Ek :
-    forall var var_type init_type env next_cont val env',
-    env' = env_extend var var_type val env ->
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Var_Declaration_Ek var var_type env next_cont)
-              init_type)
-            val)
-         (Forward_Configuration next_cont env')
-
-  (** <ExpressionEK(ρ, κE, κS), val>pass ==> <κS, ρ>forward *)
-  | Pass_Expression_Ek :
-    forall env ret_cont next_cont val val_type,
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Expression_Ek env ret_cont next_cont)
-              val_type)
-            val)
-         (Forward_Configuration next_cont env)
-
-  (** <MethodInvocationEK(name, arg, ρ, κE), null)pass ==>
-        <HaltEK, null>pass *)
-  | Pass_Method_Invocation_Ek_Null :
-    forall name arg_expr arg_type env ret_cont expected_rcvr_type,
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Method_Invocation_Ek name arg_expr env ret_cont)
-              expected_rcvr_type)
-            (mk_runtime_value None))
-         (Value_Passing_Configuration
-            (Expression_Continuation
-              Halt_Ek
-              arg_type)
-            (mk_runtime_value None))
-
-  (** <PropertyGetEK(name, κE), null)pass ==> <HaltEK, null>pass *)
-  | Pass_Property_Get_Ek_Null :
-    forall name ret_cont expected_rcvr_type,
-    step (Value_Passing_Configuration
-            (Expression_Continuation
-              (Property_Get_Ek name ret_cont)
-              expected_rcvr_type)
-            (mk_runtime_value None))
-         (Value_Passing_Configuration
-            (Expression_Continuation
-              Halt_Ek
-              expected_rcvr_type)
-            (mk_runtime_value None)).
-
-(* TODO(dmitryas): Add transitions to final states. *)
-
-
-(** Well-formedness property over configurations is understood as the property
-  of being a valid l.h.s. to the [step] relation.  The abstract machine may or
-  may not end up in a well-formed configuration several steps after its
-  configuration was well-formed. *)
-Inductive configuration_wf : configuration -> Prop :=
-
-  (** Well-formed variable-gets should have the variable in the environment. *)
-  | Eval_Variable_Get_Configuration_Wf :
-    forall var env ret_cont,
-    env_in var env ->
-    configuration_wf
-      (Eval_Configuration
-        (E_Variable_Get (Variable_Get var))
-        env ret_cont)
-
-  (** Configurations that are the beginning of a method-invocation evaluation
-    are well-formed if the expression that represents the receiver is
-    well-typed, because the machine proceed to evaluation of the receiver, and
-    the continuation that awaits for the receiver value should be typed. *)
-  | Eval_Method_Invocation_Configuration_Wf :
-    forall rcvr_expr rcvr_type name arg_expr ref env ret_cont,
-    expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
-    configuration_wf
-      (Eval_Configuration
-        (E_Invocation_Expression (IE_Method_Invocation
-          (Method_Invocation rcvr_expr (Name name) (Arguments arg_expr) ref)))
-        env ret_cont)
-
-  (** Configurations that are the beginning of a property-get evaluation are
-    well-formed if the receiver expression is well-typed, because the machine
-    always proceed to evaluation of the receiver, and the continuation that
-    awaits for the receiver value should be typed. *)
-  | Eval_Property_Get_Configuration_Wf :
-    forall rcvr_expr rcvr_type name env ret_cont,
-    expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
-    configuration_wf
-      (Eval_Configuration
-        (E_Property_Get (Property_Get rcvr_expr (Name name)))
-        env ret_cont)
-
-  (** A constructor invocation is well-formed if the referred class exists in
-    the class environment. *)
-  | Eval_Constructor_Invocation_Configuration_Wf :
-    forall class_id env ret_cont,
-    NatMap.In class_id CE ->
-    configuration_wf
-      (Eval_Configuration
-        (E_Invocation_Expression (IE_Constructor_Invocation
-          (Constructor_Invocation class_id)))
-        env ret_cont)
-
-  (** TODO(dmitryas): Write descriptive comment here. *)
-  | Exec_Variable_Declaration_Init_Wf :
-  forall var var_type init_expr init_type env ret_cont next_cont,
-    expression_type CE (env_to_type_env env) init_expr = Some init_type ->
-    configuration_wf
-      (Exec_Configuration
-        (S_Variable_Declaration
-          (Variable_Declaration var var_type (Some init_expr)))
-        env ret_cont next_cont)
-
-  (** TODO(dmitryas): Write descriptive comment here. *)
-  | Exec_Variable_Declaration_Non_Init_Wf :
-    forall var var_type env ret_cont next_cont,
-    configuration_wf
-      (Exec_Configuration
-        (S_Variable_Declaration
-          (Variable_Declaration var var_type None))
-        env ret_cont next_cont)
-
-  (** TODO(dmitryas): Write descriptive comment here. *)
-  | Exec_Return_Statement_Wf :
-    forall expr env ret_cont next_cont,
-    configuration_wf
-      (Exec_Configuration
-        (S_Return_Statement (Return_Statement expr))
-        env ret_cont next_cont)
-
-  (** TODO(dmitryas): Write descriptive comment here. *)
-  | Exec_Expression_Statement_Wf :
-    forall expr expr_type env ret_cont next_cont,
-    expression_type CE (env_to_type_env env) expr = Some expr_type ->
-    configuration_wf
-      (Exec_Configuration
-        (S_Expression_Statement (Expression_Statement expr))
-        env ret_cont next_cont)
-
-  (** TODO(dmitryas): Write descriptive comment here. *)
-  | Exec_Block_Wf :
-    forall stmts env ret_cont next_cont,
-    configuration_wf
-      (Exec_Configuration (S_Block (Block stmts)) env ret_cont next_cont)
-
-  (** These configurations pass the receiver to the continuation that is the
-    rest of the method invocation.  These configurations are well-formed if the
-    argument expression is well-typed, because the machine procedes to the
-    evaluation of the argument, and the expression continuation that awaits for
-    the argument value needs to be typed. *)
-  | Pass_Method_Invocation_Ek_Non_Null_Configuration_Wf :
-    forall name arg_expr arg_type env ret_cont
-        expected_rcvr_type rcvr_type rcvr_val,
-    runtime_type rcvr_val = Some rcvr_type ->
-    expression_type CE (env_to_type_env env) arg_expr = Some arg_type ->
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Method_Invocation_Ek name arg_expr env ret_cont)
-          expected_rcvr_type)
-        rcvr_val)
-
-  (** These configurations pass the evaluated argument to the rest of the
-    method invocation.  The precondition is that the method with such name
-    exists. *)
-  | Pass_Invocation_Ek_Configuration_Wf :
-    forall rcvr_val name ret_cont arg_val arg_type env,
-    method_exists (runtime_type rcvr_val) name ->
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Invocation_Ek rcvr_val name env ret_cont)
-          arg_type)
-        arg_val)
-
-  (** These configurations pass the evaluated receiver to the rest of the
-    property get.  The preconditions is that the getter with such name
-    exists. *)
-  | Pass_Property_Get_Ek_Non_Null_Configuration_Wf :
-    forall name ret_cont expected_rcvr_type rcvr_type rcvr_val,
-    runtime_type rcvr_val = Some rcvr_type ->
-    getter_exists (runtime_type rcvr_val) name ->
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Property_Get_Ek name ret_cont)
-          expected_rcvr_type)
-        rcvr_val)
-
-  (** In the currently formalized subset of Kernel all forward configurations
-    are well-formed.  The machine either proceeds to the execution of a
-    a statement or proceeds to the next continuation. *)
-  | Forward_Configuration_Wf :
-    forall next_cont env,
-    configuration_wf (Forward_Configuration next_cont env)
-
-  (** TODO(dmitryas): Write descriptive comments. *)
-  | Pass_Expression_Ek_Configuration_Wf :
-    forall env ret_cont next_cont val val_type,
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Expression_Ek env ret_cont next_cont)
-          val_type)
-        val)
-
-  (** TODO(dmitryas): Write descriptive comments. *)
-  | Pass_Var_Declaration_Ek_Configuration_Wf :
-    forall var var_type env next_cont init_type val,
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Var_Declaration_Ek var var_type env next_cont)
-          init_type)
-        val)
-
-  (** Invoking a method on `null` always puts the abstract machine in a final
-    state, so passing `null` to MethodInvocationEK is always well-formed. *)
-  | Pass_Method_Invocation_Ek_Null_Configuration_Wf :
-    forall name arg_expr env ret_cont rcvr_type rcvr_val,
-    runtime_type rcvr_val = None ->
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation
-          (Method_Invocation_Ek name arg_expr env ret_cont)
-          rcvr_type)
-        rcvr_val)
-
-  (** Getting a property of `null` always puts the abstract machine in a final
-    state, so passing `null` to propertyGetEK is always well-formed. *)
-  | Pass_Property_Get_Ek_Null_Configuration_Wf :
-    forall name ret_cont rcvr_type rcvr_val,
-    runtime_type rcvr_val = None ->
-    configuration_wf
-      (Value_Passing_Configuration
-        (Expression_Continuation (Property_Get_Ek name ret_cont) rcvr_type)
-        rcvr_val).
-
-
-Inductive configuration_final : configuration -> Prop :=
-
-  | Configuration_Final :
-    forall val ret_type,
-    configuration_final
-      (Value_Passing_Configuration
-        (Expression_Continuation Halt_Ek ret_type)
-        val).
-
-
-Inductive ref_in_dart_type : nat -> dart_type -> Prop :=
-
-  | RDT_Interface_Type :
-    forall ref,
-    ref_in_dart_type ref (DT_Interface_Type (Interface_Type ref))
-
-  | RDT_Function_Type :
-    forall ref param_type ret_type,
-    (ref_in_dart_type ref param_type \/
-     ref_in_dart_type ref ret_type) ->
-    ref_in_dart_type ref (DT_Function_Type
-      (Function_Type param_type ret_type)).
-
-
-Inductive dart_type_valid : option dart_type -> Prop :=
-
-  | DTV_Null :
-    dart_type_valid None
-
-  | DTV_Non_Null :
-    forall class_id type,
-    ref_in_dart_type class_id type ->
-    NatMap.In class_id CE ->
-    dart_type_valid (Some type).
-
-
-Inductive runtime_value_valid (val : runtime_value) : Prop :=
-
-  | RTV_Not_Null :
-    forall intf type,
-    (runtime_type val) = Some type ->
-    dart_type_valid (Some type) ->
-    value_of_type val intf (runtime_type val) ->
-    runtime_value_valid val
-
-  | RTV_Null :
-    value_of_type val (mk_interface nil nil) None ->
-    runtime_value_valid val.
-
-
-(** [expression_wf] is a well-formedness condition for expression w.r.t. the
-  class and member environments.  It requires that all class and member
-  references in the expression are present in [CE] and [ME] respectively. *)
-Inductive expression_wf : expression -> Prop :=
-
-  | EXPWF_Variable_Get :
-    forall var_get_expr,
-    expression_wf (E_Variable_Get var_get_expr)
-
-  | EXPWF_Property_Get :
-    forall rcvr_expr name,
-    expression_wf rcvr_expr ->
-    expression_wf (E_Property_Get (Property_Get rcvr_expr name))
-
-  | EXPWF_Method_Invocation :
-    (* TODO(dmitryas): Remove [ref] when the corresponding element is removed
-      from the AST. *)
-    forall rcvr_expr name arg_expr ref,
-    expression_wf rcvr_expr ->
-    expression_wf arg_expr ->
-    expression_wf (E_Invocation_Expression (IE_Method_Invocation
-      (Method_Invocation rcvr_expr name (Arguments arg_expr) ref)))
-
-  | EXPWF_Constructor_Invocation :
-    forall ref,
-    NatMap.In ref CE ->
-    expression_wf (E_Invocation_Expression (IE_Constructor_Invocation
-      (Constructor_Invocation ref))).
-
-
-(** [statement_wf] is a property that is analogous to [expression_wf], but is
-  defined for statements. *)
-Inductive statement_wf : statement -> Prop :=
-
-  | STWF_Expression_Statement :
-    forall expr,
-    expression_wf expr ->
-    statement_wf (S_Expression_Statement (Expression_Statement expr))
-
-  | STWF_Block_Empty :
-    statement_wf (S_Block (Block nil))
-
-  | STWF_Block_Non_Empty :
-    forall stmt stmts,
-    statement_wf stmt ->
-    statement_wf (S_Block (Block stmts)) ->
-    statement_wf (S_Block (Block (stmt :: stmts)))
-
-  | STWF_Return_Statement :
-    forall expr,
-    expression_wf expr ->
-    statement_wf (S_Return_Statement (Return_Statement expr))
-
-  | STWF_Variable_Declaration_Non_Init :
-    forall var_id type,
-    (forall class_id,
-      ref_in_dart_type class_id type -> NatMap.In class_id CE) ->
-    statement_wf (S_Variable_Declaration
-      (Variable_Declaration var_id type None))
-
-  | STWF_Variable_Declaration_Init :
-    forall var_id type init_expr,
-    dart_type_valid (Some type) ->
-    expression_wf init_expr ->
-    statement_wf (S_Variable_Declaration
-      (Variable_Declaration var_id type (Some init_expr))).
-
-
-(** [environment_valid] is a property of environment validity with respect
-  to the class and method environments.  For each variable in the environment
-  there should be a valid interface, so that [value_of_type] predicate for the
-  variable is true. *)
-Inductive environment_valid : environment -> Prop :=
-
-  | EV_Empty :
-    environment_valid nil
-
-  | EV_Non_Empty_Null :
-    forall entry env,
-    dart_type_valid (Some (var_type entry)) ->
-    (runtime_type (value entry)) = None ->
-    environment_valid env ->
-    environment_valid (entry :: env)
-
-  | EV_Non_Empty_Non_Null :
-    forall entry env,
-    dart_type_valid (Some (var_type entry)) ->
-    (runtime_type (value entry)) = Some (var_type entry) ->
-    environment_valid env ->
-    environment_valid (entry :: env).
-
-
-(** The given syntactic type is accepted by the given expression continuation.
-
-  None is accepted as the second argument, because runtime type of values can
-  be checkec agains the expression continuation. *)
-Inductive econt_accepts :
-    expression_continuation -> option dart_type -> Prop :=
-
-  | EA_Null :
-    forall econt,
-    econt_accepts econt None
-
-  | EA_Non_Null :
-    forall cont expected_type type,
-    type <: expected_type ->
-    econt_accepts
-      (Expression_Continuation cont expected_type)
-      (Some type).
-
-
-(** The syntactic type of the expression matches the syntactic type of the
-  value expected by the expression continuation. *)
-Inductive econt_accepts_expr :
-    expression_continuation -> expression -> environment -> Prop :=
-
-  | Econt_Accepts_Expr :
-    forall econt expr env expr_type,
-    expression_type CE (env_to_type_env env) expr = Some expr_type ->
-    econt_accepts econt (Some expr_type) ->
-    econt_accepts_expr econt expr env.
-
-
-(** The syntactic type returned by the statement (if any) matches the syntactic
-  type of the value expected by the expression continuation. *)
-Inductive econt_accepts_stmt :
-    expression_continuation -> statement -> environment -> Prop :=
-
-  | Econt_Accepts_Stmt :
-    forall econt stmt env ret_type te,
-    statement_type CE (env_to_type_env env) stmt ret_type = Some te ->
-    econt_accepts econt (Some ret_type) ->
-    econt_accepts_stmt econt stmt env.
-
-
-(** The syntactic type of the value matches the syntactic type of the value
-  expected by the expression continuation. *)
-Definition econt_accepts_val :
-    expression_continuation -> runtime_value -> Prop :=
-  fun econt val => econt_accepts econt (runtime_type val).
-
-
-(** Each free variable referenced from the expression is present in the
-  environment. *)
-Inductive eval_environment_sufficient : environment -> expression -> Prop :=
-
-  | EES_Variable_Get :
-    forall var env,
-    env_in var env ->
-    eval_environment_sufficient env (E_Variable_Get (Variable_Get var))
-
-  | EES_Property_Get :
-    forall expr name env,
-    eval_environment_sufficient env expr ->
-    eval_environment_sufficient env (E_Property_Get (Property_Get expr name))
-
-  | EES_Constructor_Invocation :
-    forall class_id env,
-    eval_environment_sufficient
-      env
-      (E_Invocation_Expression
-        (IE_Constructor_Invocation
-          (Constructor_Invocation class_id)))
-
-  | EES_Method_Invocation :
-    (* TODO(dmitryas): Remove ref when it's removed from the AST. *)
-    forall rcvr_expr arg_expr name ref env,
-    eval_environment_sufficient env rcvr_expr ->
-    eval_environment_sufficient env arg_expr ->
-    eval_environment_sufficient
-      env
-      (E_Invocation_Expression
-        (IE_Method_Invocation
-          (Method_Invocation rcvr_expr name (Arguments arg_expr) ref))).
-
-
-(** [exec_environment_sufficient] represents the property of the environment
-  w.r.t. the given statement.  The property shows if the given environment is
-  sufficient to evaluate all expressions in the given statement. *)
-Inductive exec_environment_sufficient : environment -> statement -> Prop :=
-
-  | EES_Expression_Statement :
-    forall env expr,
-    eval_environment_sufficient env expr ->
-    exec_environment_sufficient
-      env
-      (S_Expression_Statement (Expression_Statement expr))
-
-  | EES_Block_Empty :
-    forall env,
-    exec_environment_sufficient env (S_Block (Block nil))
-
-  | EES_Block_Non_Empty :
-    forall env stmt stmts,
-    exec_environment_sufficient env stmt ->
-    exec_environment_sufficient env (S_Block (Block stmts)) ->
-    exec_environment_sufficient env (S_Block (Block (stmt :: stmts)))
-
-  | EES_Return_Statement :
-    forall env expr,
-    eval_environment_sufficient env expr ->
-    exec_environment_sufficient
-      env
-      (S_Return_Statement (Return_Statement expr))
-
-  | EES_Variable_Declaration_Non_Init :
-    forall env var type,
-    exec_environment_sufficient
-      env
-      (S_Variable_Declaration (Variable_Declaration var type None))
-
-  | EES_Variable_Declaration_Init :
-    forall env var type init_expr,
-    eval_environment_sufficient env init_expr ->
-    exec_environment_sufficient
-      env
-      (S_Variable_Declaration
-        (Variable_Declaration var type (Some init_expr))).
-
-
-(** Validity property for expression continuations [econt_valid] and statement
-  continuations [scont_valid] is mutually inductive, because instances of one
-  may refer to instances of the other. *)
-Inductive econt_valid : expression_continuation -> Prop :=
-
-  | CV_Expression_Ek :
-    forall expr_type env ret_cont next_cont,
-    environment_valid env ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    dart_type_valid (Some expr_type) ->
-    econt_valid
-      (Expression_Continuation
-        (Expression_Ek env ret_cont next_cont)
-        expr_type)
-
-  | CV_Method_Invocation_Ek :
-    forall rcvr_type name arg_exp arg_type ret_type env ret_cont,
-    environment_valid env ->
-    dart_type_valid (Some rcvr_type) ->
-    method_accepts (Some rcvr_type) name (Some arg_type) ->
-    method_returns (Some rcvr_type) name ret_type ->
-    expression_wf arg_exp ->
-    eval_environment_sufficient env arg_exp ->
-    expression_type CE (env_to_type_env env) arg_exp = Some arg_type ->
-    dart_type_valid (Some arg_type) ->
-    econt_valid ret_cont ->
-    dart_type_valid (Some ret_type) ->
-    econt_accepts ret_cont (Some ret_type) ->
-    econt_valid
-      (Expression_Continuation
-        (Method_Invocation_Ek name arg_exp env ret_cont)
-        rcvr_type)
-
-  | CV_Invocation_Ek :
-    forall rcvr_val name env ret_cont arg_type ret_type,
-    environment_valid env ->
-    runtime_value_valid rcvr_val ->
-    method_accepts (runtime_type rcvr_val) name (Some arg_type) ->
-    method_returns (runtime_type rcvr_val) name ret_type ->
-    dart_type_valid (Some arg_type) ->
-    econt_valid ret_cont ->
-    dart_type_valid (Some ret_type) ->
-    econt_accepts ret_cont (Some ret_type) ->
-    econt_valid
-      (Expression_Continuation
-        (Invocation_Ek rcvr_val name env ret_cont)
-        arg_type)
-
-  | CV_Property_Get_Ek :
-    forall name ret_cont rcvr_type ret_type,
-    dart_type_valid (Some rcvr_type) ->
-    getter_returns (Some rcvr_type) name ret_type ->
-    econt_valid ret_cont ->
-    dart_type_valid (Some ret_type) ->
-    econt_accepts ret_cont (Some ret_type) ->
-    econt_valid
-      (Expression_Continuation
-        (Property_Get_Ek name ret_cont)
-        rcvr_type)
-
-  | CV_Var_Declaration_Ek :
-    forall var var_type env next_cont init_type,
-    environment_valid env ->
-    dart_type_valid (Some var_type) ->
-    dart_type_valid (Some init_type) ->
-    init_type <: var_type ->
-    scont_valid next_cont ->
-    econt_valid
-      (Expression_Continuation
-        (Var_Declaration_Ek var var_type env next_cont)
-        init_type)
-
-with scont_valid : statement_continuation -> Prop :=
-
-  | CV_Exit_Sk :
-    forall ret_cont val,
-    econt_valid ret_cont ->
-    runtime_value_valid val ->
-    econt_accepts_val ret_cont val ->
-    scont_valid (Exit_Sk ret_cont val)
-
-  | CV_Block_Sk_Empty :
-    forall env ret_cont next_cont,
-    environment_valid env ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk nil env ret_cont next_cont)
-
-  | CV_Block_Sk_Expression_Statement :
-    forall stmt expr expr_type stmts env ret_cont next_cont,
-    environment_valid env ->
-    stmt = S_Expression_Statement (Expression_Statement expr) ->
-    statement_wf stmt ->
-    expression_type CE (env_to_type_env env) expr = Some expr_type ->
-    scont_valid (Block_Sk stmts env ret_cont next_cont) ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
-  | CV_Block_Sk_Block :
-    forall stmt block_stmts stmts env ret_cont next_cont,
-    environment_valid env ->
-    stmt = S_Block (Block block_stmts) ->
-    statement_wf stmt ->
-    scont_valid (Block_Sk stmts env ret_cont next_cont) ->
-    scont_valid
-      (Block_Sk block_stmts env ret_cont
-        (Block_Sk stmts env ret_cont next_cont)) ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
-  | CV_Block_Sk_Return_Statement :
-    forall stmt expr expr_type stmts env ret_cont next_cont,
-    environment_valid env ->
-    stmt = S_Return_Statement (Return_Statement expr) ->
-    statement_wf stmt ->
-    expression_type CE (env_to_type_env env) expr = Some expr_type ->
-    dart_type_valid (Some expr_type) ->
-    econt_valid ret_cont ->
-    econt_accepts ret_cont (Some expr_type) ->
-    (* TODO(dmitryas): Do we really need the validity of the dead code? *)
-    scont_valid (Block_Sk stmts env ret_cont next_cont) ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
-  | CV_Block_Sk_Variable_Declaration_Init :
-    forall stmt var var_type init_expr init_expr_type
-        stmts env env' ret_cont next_cont,
-    environment_valid env ->
-    stmt = S_Variable_Declaration
-      (Variable_Declaration var var_type (Some init_expr)) ->
-    statement_wf stmt ->
-    expression_type CE (env_to_type_env env) init_expr = Some init_expr_type ->
-    init_expr_type <: var_type ->
-    env' = env_extend var var_type (mk_runtime_value (Some var_type)) env ->
-    scont_valid (Block_Sk stmts env' ret_cont next_cont) ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
-  | CV_Block_Sk_Variable_Declaration_Non_Init :
-    forall stmt var var_type stmts env env' ret_cont next_cont,
-    environment_valid env ->
-    stmt = S_Variable_Declaration
-      (Variable_Declaration var var_type None) ->
-    statement_wf stmt ->
-    env' = env_extend var var_type (mk_runtime_value None) env ->
-    scont_valid (Block_Sk stmts env' ret_cont next_cont) ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont).
-
-
-Inductive configuration_valid : configuration -> Prop :=
-
-  | Eval_Configuration_Valid :
-    forall exp env cont,
-    expression_wf exp ->
-    environment_valid env ->
-    econt_valid cont ->
-    eval_environment_sufficient env exp ->
-    econt_accepts_expr cont exp env ->
-    configuration_valid (Eval_Configuration exp env cont)
-
-  | Exec_Configuration_Valid :
-    forall stmt env ret_cont next_cont,
-    statement_wf stmt ->
-    environment_valid env ->
-    econt_valid ret_cont ->
-    scont_valid next_cont ->
-    exec_environment_sufficient env stmt ->
-    econt_accepts_stmt ret_cont stmt env ->
-    configuration_valid (Exec_Configuration stmt env ret_cont next_cont)
-
-  | Value_Passing_Configuration_Valid :
-    forall cont val,
-    econt_valid cont ->
-    runtime_value_valid val ->
-    econt_accepts_val cont val ->
-    configuration_valid (Value_Passing_Configuration cont val)
-
-  | Forward_Configuration_Valid :
-    forall cont env,
-    scont_valid cont ->
-    environment_valid env ->
-    configuration_valid (Forward_Configuration cont env).
-
-
-Inductive steps : configuration -> configuration -> Prop :=
-
-  | steps_zero :
-    forall conf,
-    steps conf conf
-
-  | steps_trans_right :
-    forall conf1 conf2 conf3,
-    steps conf1 conf2 ->
-    step conf2 conf3 ->
-    steps conf1 conf3.
-
-
-End OperationalSemantics.
diff --git a/pkg/kernel/coq/OperationalSemanticsProof.v b/pkg/kernel/coq/OperationalSemanticsProof.v
deleted file mode 100644
index 5cbbb77..0000000
--- a/pkg/kernel/coq/OperationalSemanticsProof.v
+++ /dev/null
@@ -1,717 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file. *)
-
-
-Require Import Coq.Lists.SetoidList.
-Require Import Coq.Init.Wf.
-Require Import Omega.
-
-Require Import Common.
-Require Import Syntax.
-Require Import ObjectModel.
-Require Import OperationalSemantics.
-
-Import Common.NatMapFacts.
-Import Common.MoreNatMapFacts.
-Import ObjectModel.Subtyping.
-
-
-Section OperationalSemanticsSpec.
-
-
-(** The well-formedness hypothesis is that the environments are built via
-  [lib_to_env] function from the object model module.  [program_wf] theorem
-  defined there provides the rest of the well-formedness properties. *)
-Variable L  : library.
-Variable CE : class_env.
-Variable ME : member_env.
-
-Hypothesis program_wf_hyp: lib_to_env L = (CE, ME).
-
-
-(** Auxiliary well-formedness hypothesis that should be a corollary of
-  [program_wf_hyp], but requires additional facts about the object model to be
-  proven. *)
-Inductive ref_in_intf : nat -> interface -> Prop :=
-
-  | RI_Method :
-    forall ref proc_desc intf,
-    List.In proc_desc (procedures intf) ->
-    ref_in_dart_type ref (DT_Function_Type (pr_type proc_desc)) ->
-    ref_in_intf ref intf
-
-  | RI_Getter :
-    forall ref get_desc intf,
-    List.In get_desc (getters intf) ->
-    ref_in_dart_type ref (gt_type get_desc) ->
-    ref_in_intf ref intf.
-
-Hypothesis intf_refs_wf:
-  forall class_id intf ref,
-  NatMap.MapsTo class_id intf CE ->
-  ref_in_intf ref intf ->
-  NatMap.In ref CE.
-
-
-(** Yet another hypothesis about well-formedness of getters. *)
-Hypothesis program_getters_wf:
-  forall class_id intf get_desc,
-  NatMap.MapsTo class_id intf CE ->
-  List.In get_desc (getters intf) ->
-  NatMap.In (gt_ref get_desc) ME.
-
-
-Lemma runtime_value_interface_procedures_wf :
-  forall val intf type_opt proc_desc,
-  value_of_type CE ME val intf type_opt ->
-  List.In proc_desc (procedures intf) ->
-  NatMap.In (pr_ref proc_desc) ME.
-Proof.
-  intros. destruct H.
-
-  (* Case 1. Value of Interface Type. *)
-  pose proof (program_wf L CE ME class_id intf proc_desc program_wf_hyp).
-  apply H3.
-  apply NatMapFacts.find_mapsto_iff. auto.
-  auto.
-
-  (* Case 2. Value of Function Type. *)
-  rewrite H in H0.
-  pose proof (List.in_inv H0).
-  destruct H4.
-    rewrite <- H4. simpl. apply MoreNatMapFacts.maps_in_mapsto.
-      apply MoreNatMapFacts.maps_mapsto_in. exists (M_Procedure proc).
-      auto.
-    pose proof (List.in_nil H4). contradiction.
-
-  (* Case 3. Null Value. *)
-  rewrite H in H0. pose proof (List.in_nil H0). contradiction.
-Qed.
-
-
-Lemma method_exists_desc :
-  forall type name,
-  method_exists CE ME type name ->
-  (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
-    together the interface and the type, avoiding the construction of the
-    value. *)
-  exists intf desc,
-    (value_of_type CE ME (mk_runtime_value type) intf type /\
-      List.In desc (procedures intf) /\
-      ((pr_name desc) = name)%string).
-Proof.
-  intros. destruct H; (
-
-    (* Cases of Interface Type and Function Type are analogous. *)
-    exists intf, desc; split; auto
-
-  ).
-Qed.
-
-
-Lemma subtype_means_equals :
-  forall type_pair, subtype type_pair = true -> fst type_pair = snd type_pair.
-Proof.
-  intro.
-  apply well_founded_ind with (R := pair_size_order) (a := type_pair).
-  apply pair_size_order_wf.
-  intros.
-
-  assert ((fst x) <: (snd x)).
-    destruct x. simpl. auto.
-  destruct (fst x) eqn:?. destruct (snd x) eqn:?.
-  (* t1 : Interface Type, t2 : Interface Type. *)
-  simplify_subtypes.
-  apply N.eqb_eq in H1. rewrite H1. reflexivity.
-  (* t1 : Interface Type, t2 : Function Type. *)
-  simplify_subtypes.
-  destruct (snd x) eqn :?.
-  (* t1 : Function Type, t2 : Interface Type. *)
-  simplify_subtypes.
-  (* t1 : Function Type, t2 : Function Type. *)
-  simplify_subtypes.
-  apply andb_true_iff in H1. destruct H1.
-  assert (d = d1).
-    apply H with (y := (d, d1)).
-    unfold pair_size_order. destruct x.
-    simpl in Heqd. simpl in Heqd0. rewrite Heqd, Heqd0.
-    unfold pair_size. simpl.
-    omega.
-    auto.
-  assert (d2 = d0).
-    apply H with (y := (d2, d0)).
-    unfold pair_size_order. destruct x.
-    simpl in Heqd. simpl in Heqd0. rewrite Heqd, Heqd0.
-    unfold pair_size. simpl.
-    omega.
-    auto.
-  rewrite H3, H4.
-  reflexivity.
-Qed.
-
-
-Lemma structural_subtype_methods :
-  forall type1 type2 name,
-  method_exists CE ME (Some type1) name ->
-  type2 <: type1 ->
-  method_exists CE ME (Some type2) name.
-Proof.
-  intros.
-  apply subtype_means_equals in H0. simpl in H0. rewrite H0. auto.
-Qed.
-
-
-Lemma structural_subtype_getters :
-  forall type1 type2 name,
-  getter_exists CE ME (Some type1) name ->
-  type2 <: type1 ->
-  getter_exists CE ME (Some type2) name.
-Proof.
-  intros.
-  apply subtype_means_equals in H0. simpl in H0. rewrite H0. auto.
-Qed.
-
-
-Theorem step_configuration_wf :
-  forall conf1, configuration_wf CE ME conf1 ->
-  exists conf2, step CE ME conf1 conf2.
-Proof.
-  intros.
-
-  (* Construct the second configuration from the preconditions of
-    well-formedness of the first configuration. *)
-  destruct H.
-
-  (* Case 1. Eval Variable Get. *)
-  unfold env_in in H.
-  destruct (
-    List.find
-      (fun entry : env_entry => Nat.eqb var (var_ref entry))
-      env
-  ) eqn:?; try contradiction.
-  exists (Value_Passing_Configuration ret_cont (value e)).
-  constructor.
-  unfold env_get. auto.
-
-  (* Case 2. Eval Method Invocation. *)
-  exists
-    (Eval_Configuration rcvr_expr env
-      (Expression_Continuation
-        (Method_Invocation_Ek name arg_expr env ret_cont)
-        rcvr_type)).
-  constructor. auto.
-
-  (* Case 3. Eval Property Get. *)
-  exists
-    (Eval_Configuration rcvr_expr env
-      (Expression_Continuation
-        (Property_Get_Ek name ret_cont)
-        rcvr_type)).
-  constructor. auto.
-
-  (* Case 4. Eval Constructor Invocation. *)
-  pose proof (MoreNatMapFacts.maps_in_mapsto interface CE class_id H).
-  destruct H0 as (intf & H1).
-  set (type := DT_Interface_Type (Interface_Type class_id)).
-  set (new_val := mk_runtime_value (Some type)).
-  exists (Value_Passing_Configuration ret_cont new_val).
-  constructor 14 with (intf := intf) (type_opt := Some type); try auto.
-  constructor 1 with (class_id := class_id); try (simpl; auto).
-  apply NatMapFacts.find_mapsto_iff. auto.
-
-  (* Case 6. Exec Variable Declaration with Initializer. *)
-  exists
-    (Eval_Configuration init_expr env
-      (Expression_Continuation
-        (Var_Declaration_Ek var var_type env next_cont)
-        init_type)).
-  constructor. auto.
-
-  (* Case 7. Exec Variable Declaration without Initializer. *)
-  set (null_val := mk_runtime_value None).
-  set (env' := env_extend var var_type null_val env).
-  exists (Forward_Configuration next_cont env').
-  constructor 15 with (null_val := null_val).
-    constructor 3. simpl. congruence.
-    simpl. congruence.
-    trivial. trivial.
-
-  (* Case 8. Exec Return Statement. *)
-  exists (Eval_Configuration expr env ret_cont).
-  constructor.
-
-  (* Case 9. Exec Expression Statement. *)
-  exists
-    (Eval_Configuration expr env
-      (Expression_Continuation
-        (Expression_Ek env ret_cont next_cont)
-        expr_type)).
-  constructor. auto.
-
-  (* Case 10. Exec Block. *)
-  destruct stmts eqn:?.
-
-    (* Case 10.1. Exec Empty Block. *)
-    exists (Forward_Configuration next_cont env).
-    constructor.
-
-    (* Case 10.2. Exec Non-Empty Block. *)
-    exists (Exec_Configuration s env ret_cont
-      (Block_Sk l env ret_cont next_cont)).
-    constructor.
-
-  (* Case 11. Pass Value to MethodInvocationEK. *)
-  exists
-    (Eval_Configuration arg_expr env
-      (Expression_Continuation
-        (Invocation_Ek rcvr_val name env ret_cont)
-        arg_type)).
-  constructor 9 with (rcvr_type := rcvr_type). auto. auto.
-
-  (* Case 12. Pass Value to InvocationEK. *)
-  pose proof (method_exists_desc (runtime_type rcvr_val) name H).
-  destruct H0 as (intf & desc & H1). destruct H1. destruct H1.
-  pose proof
-    (runtime_value_interface_procedures_wf
-      (mk_runtime_value (runtime_type rcvr_val))
-      intf (runtime_type rcvr_val) desc H0).
-  pose proof (H3 H1).
-  apply MoreNatMapFacts.maps_in_mapsto in H4.
-  destruct H4 as (mbr & H5). destruct mbr eqn:?. destruct p eqn:?.
-    destruct f eqn:?. destruct v eqn:?.
-  set (env' := env_extend n0 d0 arg_val empty_env).
-  set (null_val := mk_runtime_value None).
-  set (next_cont := Exit_Sk ret_cont null_val).
-  exists (Exec_Configuration s env' ret_cont next_cont).
-  constructor 10 with
-      (rcvr_intf      := intf)
-      (rcvr_type_opt  := (runtime_type rcvr_val))
-      (proc_desc      := desc)
-      (func_node      := f)
-      (var_id         := n0)
-      (var_type       := d0)
-      (var_init       := o)
-      (ret_type       := d)
-      (null_val       := null_val)
-      (memb_data      := m)
-      (named_data     := n).
-    destruct rcvr_val. simpl. simpl in H0. auto.
-    auto.
-    rewrite Heqf0; auto.
-    auto.
-    trivial.
-    trivial.
-    constructor; simpl; congruence.
-
-  (* Case 13. Pass Value to PropertyGetEK. *)
-  set (type := runtime_type rcvr_val).
-  assert (mk_runtime_value type = rcvr_val).
-    destruct rcvr_val. subst type. simpl. congruence.
-  destruct H0.
-  destruct (gt_type desc) eqn:?.
-
-    (* Case 13.1. Getting a Value of Interface Type from a Value of Interface
-      Type. *)
-    assert (runtime_type rcvr_val = type).
-      rewrite <- H1. simpl. auto.
-    subst type. rewrite H1 in H2. rewrite H0 in H2.
-      destruct H2 eqn:?;
-      try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
-    assert (type0 = type).
-      rewrite e1 in H5. injection H5. intros. auto.
-    destruct i eqn:?.
-    assert (NatMap.In n CE).
-      apply intf_refs_wf with (class_id := class_id0) (intf := intf) (ref := n).
-      apply NatMapFacts.find_mapsto_iff. auto.
-      constructor 2 with (get_desc := desc).
-      auto.
-      rewrite Heqd. constructor.
-    pose proof (MoreNatMapFacts.maps_in_mapsto interface CE n H7).
-    destruct H8 as (el & H9).
-    set (ret_type := DT_Interface_Type (Interface_Type n)).
-    set (ret_intf := el).
-    set (ret_val := mk_runtime_value (Some ret_type)).
-    exists (Value_Passing_Configuration ret_cont ret_val).
-    constructor 12 with
-        (rcvr_intf      := intf)
-        (rcvr_type_opt  := Some type)
-        (memb_id        := gt_ref desc)
-        (ret_intf       := ret_intf)
-        (ret_type       := ret_type).
-      auto.
-      set (get_desc_alt := mk_getter_desc name (gt_ref desc) ret_type).
-      assert (desc = get_desc_alt).
-        destruct desc. subst get_desc_alt. simpl.
-        simpl in H4. rewrite H4.
-        simpl in Heqd. rewrite Heqd. subst ret_type.
-        congruence.
-      rewrite <- H8.
-      auto.
-    constructor 1 with (class_id := n).
-      auto.
-      apply NatMapFacts.find_mapsto_iff. subst ret_intf. auto.
-      simpl. congruence.
-
-    (* Case 13.2. Getting a Value of Function Type from a Value of Interface
-      Type. *)
-    set (ret_type := DT_Function_Type f).
-    set (ret_intf := mk_interface
-      ((mk_procedure_desc "call" (gt_ref desc) f) :: nil)
-      ((mk_getter_desc "call" (gt_ref desc) (DT_Function_Type f)) :: nil)).
-    set (ret_val := mk_runtime_value (Some ret_type)).
-
-    assert (runtime_type rcvr_val = Some type0).
-      subst type. rewrite <- H1. simpl. auto.
-    subst type. rewrite H1 in H2. rewrite H0 in H2.
-      destruct H2 eqn:?;
-      try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
-    assert (type0 = type).
-      rewrite e1 in H5. injection H5. intros. auto.
-    assert (class_id0 = class_id).
-      rewrite e in H6. rewrite H0 in H6.
-      injection H6. intros. auto.
-
-    exists (Value_Passing_Configuration ret_cont ret_val).
-    constructor 12 with
-        (rcvr_intf := intf)
-        (rcvr_type_opt := Some type)
-        (memb_id := gt_ref desc)
-        (ret_intf := ret_intf)
-        (ret_type := ret_type).
-    constructor 1 with (class_id := class_id0); auto.
-
-    set (get_desc_alt := mk_getter_desc name (gt_ref desc) ret_type).
-    assert (desc = get_desc_alt).
-      destruct desc. subst get_desc_alt. simpl.
-      simpl in H4. rewrite H4.
-      simpl in Heqd. rewrite Heqd. subst ret_type.
-      congruence.
-    rewrite <- H8. auto.
-
-    clear Heqv.
-      destruct H2;
-      try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
-    apply NatMapFacts.find_mapsto_iff in e0.
-    pose proof (program_getters_wf class_id0 intf desc e0).
-    pose proof (H10 H3).
-    apply MoreNatMapFacts.maps_in_mapsto in H11.
-    destruct H11 as (mbr & H12).
-
-    destruct mbr.
-    constructor 2 with (memb_id := gt_ref desc) (proc := p).
-    simpl. congruence.
-    simpl. congruence.
-    auto.
-    simpl. subst ret_type. congruence.
-
-    (* Case 13.3. Getting a Value from a Value of Function Type. *)
-    subst type. rewrite H1 in H2. rewrite H in H2.
-      destruct H2 eqn:?; try (
-        clear Heqv;
-        rewrite <- H1 in e1;
-        simpl in e1;
-        rewrite H0 in e1;
-        rewrite e in e1;
-        discriminate e1
-    ).
-
-    assert (ftype0 = ftype).
-      rewrite H0 in H. injection H. intros. auto.
-
-    exists (Value_Passing_Configuration ret_cont val).
-    constructor 12 with
-        (rcvr_intf := intf)
-        (rcvr_type_opt := Some type0)
-        (memb_id := gt_ref desc)
-        (ret_intf := intf)
-        (ret_type := type0).
-    rewrite H. auto.
-
-    pose proof H2.
-    rewrite e0 in H3.
-    pose proof (List.in_inv H3).
-    destruct H7.
-      clear Heqv. rewrite H7 in H3. rewrite H7 in e0. rewrite <- H7. simpl.
-        rewrite <- e0 in  H3. rewrite H5 in H7. rewrite <- H0 in H7.
-        rewrite H7. auto.
-      pose proof (List.in_nil H7). contradiction.
-    rewrite H0; rewrite <- H5; auto.
-
-    (* Case 13.4. Getting a Value from Null. *)
-    rewrite e0 in H3.
-    pose proof (List.in_nil H3).
-    contradiction.
-
-  (* Case 9. Forward. *)
-  destruct next_cont.
-
-    (* Case 9.1. Forward to Exit. *)
-    exists (Value_Passing_Configuration e r).
-    constructor.
-
-    (* Case 9.2. Forward to the Next Statement in Block. *)
-    destruct l.
-
-      (* Case 9.2.1. Block is Empty. *)
-      exists (Forward_Configuration next_cont e).
-      constructor.
-
-      (* Case 9.2.2. Block is Non-Empty. *)
-      exists (Exec_Configuration s env e0 (Block_Sk l e e0 next_cont)).
-      constructor.
-
-  (* Case 10. Pass Value to ExpressionEk. *)
-  exists (Forward_Configuration next_cont env).
-  constructor.
-
-  (* Case 11. Pass Value to VarDeclarationEk. *)
-  set (env' := env_extend var var_type val env).
-  exists (Forward_Configuration next_cont env').
-  constructor.
-  auto.
-
-  (* Case 12. Pass Value to MethodInvocationEK: No Such Method. *)
-  exists
-    (Value_Passing_Configuration
-      (Expression_Continuation Halt_Ek rcvr_type)
-      (mk_runtime_value None)).
-  assert (rcvr_val = mk_runtime_value None).
-    destruct rcvr_val. simpl in H. rewrite H. reflexivity.
-  rewrite H0.
-  constructor 19.
-
-  (* Case 13. Pass Value to PropertyGetEK: No Such Getter. *)
-  exists
-    (Value_Passing_Configuration
-      (Expression_Continuation Halt_Ek rcvr_type)
-      (mk_runtime_value None)).
-  assert (rcvr_val = mk_runtime_value None).
-    destruct rcvr_val. simpl in H. rewrite H. reflexivity.
-  rewrite H0.
-  constructor 20.
-Qed.
-
-
-Lemma configuration_valid_wf :
-  forall conf, configuration_valid CE ME conf -> configuration_wf CE ME conf.
-Proof.
-  intros. destruct H.
-
-  (* Case 1. Eval Configuration. *)
-  destruct H2.
-
-    (* Case 1.1. Eval Variable Get. *)
-    constructor. auto.
-
-    (* Case 1.2. Eval Property Get. *)
-    remember (E_Property_Get (Property_Get expr name)) as expr0.
-    destruct H3.
-    assert (
-      exists rcvr_type,
-        expression_type CE (env_to_type_env env) expr = Some rcvr_type
-    ).
-      rewrite Heqexpr0 in H3. simpl in H3.
-      destruct (expression_type CE (env_to_type_env env) expr) eqn:?;
-        try discriminate H3.
-      exists d. reflexivity.
-    destruct H5 as (rcvr_type & H6).
-    rewrite Heqexpr0. destruct name.
-    constructor 3 with (rcvr_type := rcvr_type).
-    auto.
-
-    (* Case 1.3. Eval Constructor Invocation. *)
-    constructor.
-    remember
-      (E_Invocation_Expression
-        (IE_Constructor_Invocation
-          (Constructor_Invocation class_id)))
-      as expr.
-    destruct H; try discriminate Heqexpr.
-    assert (ref = class_id).
-      injection Heqexpr. intros. auto.
-    rewrite <- H2. auto.
-
-    (* Case 1.4. Eval Method Invocation. *)
-    remember
-      (E_Invocation_Expression
-        (IE_Method_Invocation
-          (Method_Invocation rcvr_expr name (Arguments arg_expr) ref)))
-      as expr.
-    destruct H3.
-    assert (
-      exists rcvr_type,
-        expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type
-    ).
-      rewrite Heqexpr in H2. simpl in H2.
-      destruct (expression_type CE (env_to_type_env env) rcvr_expr) eqn:?;
-        try discriminate H2.
-      exists d. reflexivity.
-    destruct H4 as (rcvr_type & H5).
-    rewrite Heqexpr. destruct name.
-    constructor 2 with (rcvr_type := rcvr_type).
-    auto.
-
-  (* Case 2. Exec Configuration. *)
-  destruct H3.
-
-    (* Case 2.1. Exec Expression Statement. *)
-    remember
-      (S_Expression_Statement
-        (Expression_Statement expr))
-      as stmt.
-    destruct H4.
-    assert (
-      exists expr_type,
-        expression_type CE (env_to_type_env env) expr = Some expr_type
-    ).
-      rewrite Heqstmt in H4. simpl in H4.
-      destruct (expression_type CE (env_to_type_env env) expr) eqn:?;
-        try discriminate H4.
-      exists d. auto.
-    destruct H6 as (expr_type & H7).
-    rewrite Heqstmt.
-    constructor 8 with (expr_type := expr_type).
-    auto.
-
-    (* Case 2.2. Exec Empty Block. *)
-    constructor.
-
-    (* Case 2.3. Exec Non-Empty Block. *)
-    constructor.
-
-    (* Case 2.4. Exec Return Statement. *)
-    constructor.
-
-    (* Case 2.5. Exec Variable Declaration without Initializer. *)
-    constructor.
-
-    (* Case 2.6. Exec Variable Declaration with Initializer. *)
-    remember
-      (S_Variable_Declaration
-        (Variable_Declaration var type (Some init_expr)))
-      as stmt.
-    destruct H4.
-    assert (
-      exists init_type,
-        expression_type CE (env_to_type_env env) init_expr = Some init_type
-    ).
-      rewrite Heqstmt in H4. simpl in H4.
-      destruct (expression_type CE (env_to_type_env env) init_expr) eqn:?;
-        try discriminate H4.
-      exists d. auto.
-    destruct H6 as (init_type & H7).
-    rewrite Heqstmt.
-    constructor 5 with (init_type := init_type).
-    auto.
-
-  (* Case 3. Value Passing Configuration *)
-  destruct cont. destruct u.
-
-    (* Case 3.1. Pass Value to ExpressionEK. *)
-    constructor.
-
-    (* Case 3.2. Pass Value to MethodInvocationEK. *)
-    destruct (runtime_type val) eqn:?.
-
-      (* Case 3.2.1. Non Null Value. Actual Invocation. *)
-      remember (Expression_Continuation (Method_Invocation_Ek s e e0 e1) d)
-        as econt.
-      destruct H; try discriminate Heqecont.
-      constructor 10 with (arg_type := arg_type) (rcvr_type := d0).
-      auto.
-      auto.
-
-      (* Case 3.2.2. Null Value. No Such Method. *)
-      assert (val = mk_runtime_value None).
-        destruct val. simpl in Heqo. rewrite Heqo. reflexivity.
-      rewrite H2.
-      constructor.
-      rewrite <- H2. auto.
-
-    (* Case 3.3. Pass Value to InvocationEK. *)
-    remember (Expression_Continuation (Invocation_Ek r s e e0) d) as econt.
-    destruct H; try discriminate Heqecont.
-    remember (runtime_type rcvr_val) as rcvr_val_type.
-    destruct H3; constructor; rewrite <- Heqrcvr_val_type; auto.
-
-    (* Case 3.4. Pass Value to PropertyGetEK. *)
-    destruct (runtime_type val) eqn:?.
-    assert (val = mk_runtime_value (Some d0)).
-      destruct val. rewrite <- Heqo. simpl. reflexivity.
-
-      (* Case 3.4.1. Non Null Value. Actual Invocation. *)
-      constructor 12 with (rcvr_type := d0).
-      auto.
-      rewrite H2. simpl.
-      remember (Expression_Continuation (Property_Get_Ek s e) d) as econt.
-      destruct H1; try discriminate Heqo.
-      assert (type = d0). injection Heqo. intros. auto.
-      rewrite H3 in *.
-      remember (Expression_Continuation cont expected_type) as econt.
-      destruct H; try discriminate Heqecont.
-      remember (Some rcvr_type) as rt.
-      destruct H4.
-      assert (rcvr_type0 = rcvr_type). injection Heqrt. intros. auto.
-      rewrite H11 in *.
-      assert (rcvr_type = expected_type). injection Heqecont0. intros. auto.
-      rewrite H12 in *.
-      apply structural_subtype_getters with
-        (type1 := expected_type) (type2 := d0).
-      auto.
-      assert (name = s). injection Heqecont. intros. auto.
-      rewrite <- H13.
-      auto.
-      auto.
-
-      (* Case 3.4.2. Null Value. No Such Getter. *)
-      constructor. auto.
-
-    (* Case 3.5. Pass Value to Var Declaration. *)
-    constructor.
-
-    (* Case 3.6. Pass Value to Halt. *)
-    remember (Expression_Continuation Halt_Ek d) as econt.
-    destruct H; discriminate Heqecont.
-
-    (* Case 4. Forward Configuration. *)
-    constructor.
-Qed.
-
-
-Lemma configuration_valid_step :
-  forall conf1 conf2,
-  configuration_valid CE ME conf1 ->
-  step CE ME conf1 conf2 ->
-  configuration_valid CE ME conf2 \/ configuration_final conf2.
-Proof.
-  admit.
-Admitted.
-
-
-Theorem progress:
-  forall conf1,
-  configuration_valid CE ME conf1 ->
-  exists conf2, step CE ME conf1 conf2 /\
-    (configuration_valid CE ME conf2 \/ configuration_final conf2).
-Proof.
-  intros.
-  admit.
-Admitted.
-
-
-Lemma preservation_eval:
-  forall conf1 conf2 exp val env cont val_type exp_type,
-  configuration_valid CE ME conf1 ->
-  conf1 = Eval_Configuration exp env cont ->
-  conf2 = Value_Passing_Configuration cont val ->
-  steps CE ME conf1 conf2 ->
-  expression_type CE (env_to_type_env env) exp = Some exp_type ->
-  (runtime_type val) = Some val_type ->
-  subtype (val_type, exp_type) = true.
-Proof.
-  admit.
-Admitted.
-
-
-End OperationalSemanticsSpec.
diff --git a/pkg/kernel/coq/Syntax.v b/pkg/kernel/coq/Syntax.v
deleted file mode 100644
index b508f8e..0000000
--- a/pkg/kernel/coq/Syntax.v
+++ /dev/null
@@ -1,61 +0,0 @@
-Require Export SyntaxRaw.
-Require Import Common.
-
-Scheme dart_type_ind_mutual := Induction for dart_type Sort Prop
-  with interface_type_ind_mutual := Induction for interface_type Sort Prop
-  with function_type_ind_mutual := Induction for function_type Sort Prop.
-
-Scheme expression_ind_mutual := Induction for expression Sort Prop
-  with variable_get_ind_mutual := Induction for variable_get Sort Prop
-  with property_get_ind_mutual := Induction for property_get Sort Prop
-  with invocation_expression_ind_mutual := Induction for invocation_expression Sort Prop
-  with method_invocation_ind_mutual := Induction for method_invocation Sort Prop
-  with constructor_invocation_ind_mutual := Induction for constructor_invocation Sort Prop
-  with arguments_ind_mutual := Induction for arguments Sort Prop.
-
-Scheme statement_ind_mutual := Induction for statement Sort Prop
-  with expression_statement_ind_mutual := Induction for expression_statement Sort Prop
-  with block_ind_mutual := Induction for block Sort Prop
-  with return_ind_mutual := Induction for return_statement Sort Prop
-  with variable_declaration_ind_mutual := Induction for variable_declaration Sort Prop
-.
-
-Definition dart_type_induction prop :=
-  dart_type_ind_mutual
-    prop
-    (fun i => prop (DT_Interface_Type i))
-    (fun f => prop (DT_Function_Type f)).
-
-Definition expr_induction prop :=
-  expression_ind_mutual
-    (fun e => prop e)
-    (fun v => prop (E_Variable_Get v))
-    (fun p => prop (E_Property_Get p))
-    (fun ie => prop (E_Invocation_Expression ie))
-    (fun mi => prop (E_Invocation_Expression (IE_Method_Invocation mi)))
-    (fun ci => prop (E_Invocation_Expression (IE_Constructor_Invocation ci)))
-    (fun args => let (param) := args in prop param).
-
-(* Since blocks contain lists of statements, we can't just use Scheme to
-   generate a good induction prinicple. *)
-Section Statement_Mutual_Induction.
-  Variable P : statement -> Prop.
-  Hypothesis Return : forall r, P (S_Return_Statement r).
-  Hypothesis VarDecl : forall vd, P (S_Variable_Declaration vd).
-  Hypothesis Expr : forall e, P (S_Expression_Statement e).
-  Hypothesis Blk : forall ss, Forall P ss -> P (S_Block (Block ss)).
-
-  Fixpoint statement_induction s : P s :=
-    match s with
-    | S_Return_Statement r => Return r
-    | S_Expression_Statement e => Expr e
-    | S_Variable_Declaration vd => VarDecl vd
-    | S_Block (Block ss) =>
-      let ss_all := (fix rec (ss : list statement) : Forall P ss :=
-                     match ss with
-                     | nil => Forall_nil _
-                     | (s::ss) => Forall_cons _ (statement_induction s) (rec ss)
-                     end) ss in
-      Blk ss ss_all
-    end.
-End Statement_Mutual_Induction.
diff --git a/pkg/kernel/coq/SyntaxRaw.v b/pkg/kernel/coq/SyntaxRaw.v
deleted file mode 100644
index 36c3083..0000000
--- a/pkg/kernel/coq/SyntaxRaw.v
+++ /dev/null
@@ -1,148 +0,0 @@
-Require Import Common.
-
-Inductive named_node_data : Set :=
-  | Named_Node : 
-      reference (* reference *)
-      -> named_node_data
-
-with named_node : Set :=
-  | NN_Library : library -> named_node
-  | NN_Class : class -> named_node
-  | NN_Member : member -> named_node
-
-
-with reference : Set :=
-  | Reference : 
-      nat
-      -> reference
-
-with library : Set :=
-  | Library : 
-      named_node_data
-      -> list class (* classes *)
-      -> list procedure (* procedures *)
-      -> library
-
-with class : Set :=
-  | Class : 
-      named_node_data
-      -> string (* name *)
-      -> list procedure (* procedures *)
-      -> class
-
-with member_data : Set :=
-  | Member : 
-      named_node_data
-      -> name (* name *)
-      -> member_data
-
-with member : Set :=
-  | M_Procedure : procedure -> member
-
-
-with procedure : Set :=
-  | Procedure : 
-      member_data
-      -> named_node_data
-      -> function_node (* function *)
-      -> procedure
-
-with function_node : Set :=
-  | Function_Node : 
-      variable_declaration (* positionalParameters *)
-      -> dart_type (* returnType *)
-      -> statement (* body *)
-      -> function_node
-
-with expression : Set :=
-  | E_Variable_Get : variable_get -> expression
-  | E_Property_Get : property_get -> expression
-  | E_Invocation_Expression : invocation_expression -> expression
-
-
-with variable_get : Set :=
-  | Variable_Get : 
-      nat (* variable *)
-      -> variable_get
-
-with property_get : Set :=
-  | Property_Get : 
-      expression (* receiver *)
-      -> name (* name *)
-      -> property_get
-
-with arguments : Set :=
-  | Arguments : 
-      expression (* positional *)
-      -> arguments
-
-with invocation_expression : Set :=
-  | IE_Method_Invocation : method_invocation -> invocation_expression
-  | IE_Constructor_Invocation : constructor_invocation -> invocation_expression
-
-
-with method_invocation : Set :=
-  | Method_Invocation : 
-      expression (* receiver *)
-      -> name (* name *)
-      -> arguments (* arguments *)
-      -> nat (* interfaceTargetReference *)
-      -> method_invocation
-
-with constructor_invocation : Set :=
-  | Constructor_Invocation : 
-      nat (* targetReference *)
-      -> constructor_invocation
-
-with statement : Set :=
-  | S_Expression_Statement : expression_statement -> statement
-  | S_Block : block -> statement
-  | S_Return_Statement : return_statement -> statement
-  | S_Variable_Declaration : variable_declaration -> statement
-
-
-with expression_statement : Set :=
-  | Expression_Statement : 
-      expression (* expression *)
-      -> expression_statement
-
-with block : Set :=
-  | Block : 
-      list statement (* statements *)
-      -> block
-
-with return_statement : Set :=
-  | Return_Statement : 
-      expression (* expression *)
-      -> return_statement
-
-with variable_declaration : Set :=
-  | Variable_Declaration : 
-      nat
-      -> dart_type (* type *)
-      -> option expression (* initializer *)
-      -> variable_declaration
-
-with name : Set :=
-  | Name : 
-      string (* name *)
-      -> name
-
-with dart_type : Set :=
-  | DT_Interface_Type : interface_type -> dart_type
-  | DT_Function_Type : function_type -> dart_type
-
-
-with interface_type : Set :=
-  | Interface_Type : 
-      nat (* className *)
-      -> interface_type
-
-with function_type : Set :=
-  | Function_Type : 
-      dart_type (* positionalParameters *)
-      -> dart_type (* returnType *)
-      -> function_type
-
-.
-
diff --git a/pkg/kernel/coq/_CoqProject b/pkg/kernel/coq/_CoqProject
deleted file mode 100644
index 93bae87..0000000
--- a/pkg/kernel/coq/_CoqProject
+++ /dev/null
@@ -1,9 +0,0 @@
--R . Kernel
-./Syntax.v
-./OperationalSemanticsProof.v
-./CommonTactics.v
-./Common.v
-./SyntaxRaw.v
-./ObjectModel.v
-./OperationalSemantics.v
-./CpdtTactics.v
diff --git a/pkg/kernel/coq/build.sh b/pkg/kernel/coq/build.sh
deleted file mode 100755
index 87d249e..0000000
--- a/pkg/kernel/coq/build.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-coq_makefile -f _CoqProject -o Makefile && make
diff --git a/pkg/kernel/coq/ho-interpreter.sml b/pkg/kernel/coq/ho-interpreter.sml
deleted file mode 100644
index 12a2750..0000000
--- a/pkg/kernel/coq/ho-interpreter.sml
+++ /dev/null
@@ -1,202 +0,0 @@
-(* Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-   for details.  All rights reserved.  Use of this source code is governed by a
-   BSD-style license that can be found in the LICENSE file.
- *)
-
-(* Syntax of Henry I, more or less.
-
-   Some things are different, for example ReturnStatement has an optional
-   expression.  References are implemented as SML ref types though in a real
-   implementation they would have to be option refs, provided the tree was built
-   bottom up, so that they could be initialized to ref NONE.
-
-   Integer ids are assigned to variable declarations and classes, so that they
-   can be compared for identity or so-called pointer equality.
- *)
-structure Syntax
-= struct
-    type identifier = string
-
-    datatype type_
-      = InterfaceType of {class: class ref}
-      | FunctionType of {returnType: type_, parameterType: type_}
-    and expression
-      = VariableGet of {variable: variable_declaration ref}
-      | MethodInvocation of
-          {receiver: expression,
-           name: identifier,
-           argument: expression}
-      | ConstructorInvocation of {class: class ref}
-      | PropertyGet of {receiver: expression, name: identifier}
-    and statement
-      = ExpressionStatement of {expression: expression}
-      | ReturnStatement of {expression: expression option}
-      | Block of {statements: statement list}
-    and member
-      = Class of class
-      | Procedure of procedure
-    withtype variable_declaration = {id: int, type_: type_}
-    and procedure =
-      {returnType: type_,
-       name: identifier,
-       parameter: variable_declaration,
-       body: statement}
-    and class = {id: int, procedures: procedure list}
-
-    type library = {members: member list}
-  end
-
-(* The higher-order interpreter. *)
-structure Semantics
-= struct
-    structure S = Syntax
-
-    (* The environment maps variable declaration ids to their values.  It is
-       implemented as a list of pairs.
-
-       There is a non-exhaustive pattern match which should not be reached for
-       well-formed Henry I programs.
-     *)
-    type 'a environment = (int * 'a) list
-    fun apply_env ((i, v) :: env, d: S.variable_declaration ref)
-        = if i = #id (!d) then v else apply_env (env, d)
-
-    (* - A (runtime) class is a pair of the class id and a getter suite.
-       - A getter suite is a map from getter names (identifiers) to getters.
-       - A getter is a function from receiver to result values.  In Henry I
-         getters are method tearoffs and so they have no effects (they cannot
-         throw, for example).
-       - Object values have only a class (objects have no fields in Henry I).
-         Null and NoSuchMethod are objects with distinguished classes.
-       - Functions are method tearoffs.  They also have a getter suite because
-         they can have getters (e.g., "call" or "equals").  They hold a method
-         which is a function taking the single argument and a error and return
-         continuations.
-     *)
-    datatype value
-      = ObjectValue of class
-      | FunctionValue of class * (value * (value -> unit) * (value -> unit) -> unit)
-    withtype getter = value -> value
-    and getter_suite = (S.identifier * getter) list
-    and class = int * getter_suite
-
-    (* Given a name and a value, lookup a getter which may not exist. *)
-    fun lookup_getter (name, v)
-        = let fun find_in nil
-                  = NONE
-                | find_in ((x, f) :: gs)
-                  = if name = x then SOME f else find_in gs
-          in case v
-              of ObjectValue (_, gs)
-                 => find_in gs
-               | FunctionValue ((_, gs), _)
-                 => find_in gs
-          end
-
-    (* A class table is a map from a class id to its getter suite.
-
-       There is a non-exhaustive pattern match which should not be reached for
-       well-formed Henry I programs.
-     *)
-    type class_table = (int * getter_suite) list
-    fun lookup_class (c: S.class ref, (cid, gs) :: ct)
-        = if #id (!c) = cid then gs else lookup_class (c, ct)
-
-    (* For convenience we just use a global class table because it's annoying to
-       pass it.  It is immutable and doesn't change once initialized before
-       program execution.
-     *)
-    val ct: class_table option ref = ref NONE
-    fun class_table () = Option.valOf (!ct)
-
-    (* Getter suites for builtin in classes. *)
-    (* The getter that tears off the call method of a FunctionValue is cute. *)
-    fun function_class (): class = (~1, [("call", fn v => v)])
-    fun null_class (): class = (~2, nil)
-    fun no_such_method_class(): class = (~3, nil)
-
-    fun apply (v0 as ObjectValue _, v1, ek, k)
-        = (case lookup_getter ("call", v0)
-            of NONE => ek (ObjectValue (no_such_method_class ()))
-             | SOME g => apply (g v0, v1, ek, k))
-      | apply (FunctionValue (_, f), v, ek, k)
-        = f (v, ek, k)
-
-    fun eval (S.VariableGet {variable = d}, env, ek, k)
-        = k (apply_env (env, d))
-      | eval (S.MethodInvocation {receiver = e0, name = x, argument = e1},
-              env, ek, k)
-        = eval (e0, env, ek,
-            fn v0 =>
-               (case lookup_getter (x, v0)
-                 of NONE
-                    => eval (e1, env, ek,
-                         fn _ =>
-                           ek (ObjectValue (no_such_method_class ())))
-                  | SOME g
-                    => let val f = g v0
-                       in eval (e1, env, ek, fn v1 => apply (f, v1, ek, k))
-                       end))
-      | eval (S.ConstructorInvocation {class = c}, env, ek, k)
-        = k (ObjectValue (#id (!c), lookup_class (c, class_table ())))
-      | eval (S.PropertyGet {receiver = e, name = x}, env, ek, k)
-        = eval (e, env, ek,
-            fn v =>
-               (case lookup_getter (x, v)
-                 of NONE
-                    => ek (ObjectValue (no_such_method_class ()))
-                  | SOME g
-                    => k (g v)))
-
-    fun exec (S.ExpressionStatement {expression = e}, env, rk, ek, sk)
-        = eval (e, env, ek, fn _ => sk ())
-      | exec (S.ReturnStatement {expression = NONE}, env, rk, ek, sk)
-        = rk (ObjectValue (null_class ()))
-      | exec (S.ReturnStatement {expression = SOME e}, env, rk, ek, sk)
-        = eval (e, env, ek, rk)
-      | exec (S.Block {statements = ss}, env, rk, ek, sk)
-        = exec_stmts (ss, env, rk, ek, sk)
-    and exec_stmts (nil, env, rk, ek, sk)
-        = sk ()
-      | exec_stmts (s :: ss, env, rk, ek, sk)
-        = exec (s, env, rk, ek,
-                fn () => exec_stmts (ss, env, rk, ek, sk))
-
-    (* Loading the class table.  A procedure in a class induces a getter which
-       tears off the procedure.
-     *)
-    fun process_procedure ({returnType = t,
-                            name = x,
-                            parameter = p,
-                            body = b}: S.procedure): S.identifier * getter
-        = (x, fn _ =>
-                 FunctionValue
-                     (function_class (),
-                      fn (v, ek, k) =>
-                         exec (b, [(#id p, v)], ek, k,
-                           fn () => k (ObjectValue (null_class ())))))
-
-    fun process_class ({id = n, procedures = ps}: S.class): int * getter_suite
-        = (n, List.map process_procedure ps)
-
-    fun run {members = ms}
-        = let fun process_members nil
-                  = nil
-                | process_members (S.Class c :: ms)
-                  = process_class c :: process_members ms
-                | process_members (S.Procedure p :: ms)
-                  = process_members ms
-              val _ = ct := SOME (process_members ms)
-              (* There is a non-exhaustive pattern match below which should not
-                 be possible for well-formed Henry I programs.
-               *)
-              fun find_main (S.Class c :: ms)
-                  = find_main ms
-                | find_main (S.Procedure p :: ms)
-                  = if #name p = "main" then p else find_main ms
-          in exec (#body (find_main ms), nil,
-                   fn v => print "done",
-                   fn e => print "error",
-                   fn () => print "done")
-          end
-end
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 6fdda00..4f83479 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -76,13 +76,12 @@
 import 'text/ast_to_text.dart';
 import 'type_algebra.dart';
 import 'type_environment.dart';
-import 'coq_annot.dart';
 
 /// Any type of node in the IR.
 abstract class Node {
   const Node();
 
-  accept(Visitor v);
+  R accept<R>(Visitor<R> v);
   void visitChildren(Visitor v);
 
   /// Returns the textual representation of this node for use in debugging.
@@ -115,8 +114,8 @@
   /// not available (this is the default if none is specifically set).
   int fileOffset = noOffset;
 
-  accept(TreeVisitor v);
-  visitChildren(Visitor v);
+  R accept<R>(TreeVisitor<R> v);
+  void visitChildren(Visitor v);
   transformChildren(Transformer v);
 
   /// Replaces [child] with [replacement].
@@ -174,9 +173,7 @@
 ///
 /// There is a single [reference] belonging to this node, providing a level of
 /// indirection that is needed during serialization.
-@coq
 abstract class NamedNode extends TreeNode {
-  @coqdef
   final Reference reference;
 
   NamedNode(Reference reference)
@@ -200,11 +197,9 @@
 /// Indirection between a reference and its definition.
 ///
 /// There is only one reference object per [NamedNode].
-@coqref
 class Reference {
   CanonicalName canonicalName;
 
-  @nocoq
   NamedNode node;
 
   String toString() {
@@ -271,7 +266,6 @@
 //                      LIBRARIES and CLASSES
 // ------------------------------------------------------------------------
 
-@coq
 class Library extends NamedNode
     implements Annotatable, Comparable<Library>, FileUriNode {
   /// An import path to this library.
@@ -285,15 +279,15 @@
   Uri fileUri;
 
   // TODO(jensj): Do we have a better option than this?
-  static int defaultLangaugeVersionMajor = 2;
-  static int defaultLangaugeVersionMinor = 4;
+  static int defaultLanguageVersionMajor = 2;
+  static int defaultLanguageVersionMinor = 6;
 
   int _languageVersionMajor;
   int _languageVersionMinor;
   int get languageVersionMajor =>
-      _languageVersionMajor ?? defaultLangaugeVersionMajor;
+      _languageVersionMajor ?? defaultLanguageVersionMajor;
   int get languageVersionMinor =>
-      _languageVersionMinor ?? defaultLangaugeVersionMinor;
+      _languageVersionMinor ?? defaultLanguageVersionMinor;
   void setLanguageVersion(int languageVersionMajor, int languageVersionMinor) {
     if (languageVersionMajor == null || languageVersionMinor == null) {
       throw new StateError("Trying to set langauge version 'null'");
@@ -336,7 +330,6 @@
   /// list is empty.
   List<String> problemsAsJson;
 
-  @nocoq
   final List<Expression> annotations;
 
   final List<LibraryDependency> dependencies;
@@ -344,7 +337,6 @@
   /// References to nodes exported by `export` declarations that:
   /// - aren't ambiguous, or
   /// - aren't hidden by local declarations.
-  @nocoq
   final List<Reference> additionalExports = <Reference>[];
 
   @informative
@@ -455,6 +447,10 @@
       canonicalName.getChild(class_.name).bindTo(class_.reference);
       class_.computeCanonicalNames();
     }
+    for (int i = 0; i < extensions.length; ++i) {
+      Extension extension = extensions[i];
+      canonicalName.getChild(extension.name).bindTo(extension.reference);
+    }
   }
 
   void addDependency(LibraryDependency node) {
@@ -465,7 +461,7 @@
     parts.add(node..parent = this);
   }
 
-  accept(TreeVisitor v) => v.visitLibrary(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitLibrary(this);
 
   visitChildren(Visitor v) {
     visitList(annotations, v);
@@ -473,6 +469,7 @@
     visitList(parts, v);
     visitList(typedefs, v);
     visitList(classes, v);
+    visitList(extensions, v);
     visitList(procedures, v);
     visitList(fields, v);
   }
@@ -483,6 +480,7 @@
     transformList(parts, v, this);
     transformList(typedefs, v, this);
     transformList(classes, v, this);
+    transformList(extensions, v, this);
     transformList(procedures, v, this);
     transformList(fields, v, this);
   }
@@ -566,7 +564,7 @@
     annotations.add(annotation..parent = this);
   }
 
-  accept(TreeVisitor v) => v.visitLibraryDependency(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitLibraryDependency(this);
 
   visitChildren(Visitor v) {
     visitList(annotations, v);
@@ -596,7 +594,7 @@
     annotations.add(annotation..parent = this);
   }
 
-  accept(TreeVisitor v) => v.visitLibraryPart(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitLibraryPart(this);
 
   visitChildren(Visitor v) {
     visitList(annotations, v);
@@ -622,7 +620,7 @@
   bool get isHide => !isShow;
 
   @override
-  accept(TreeVisitor v) => v.visitCombinator(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitCombinator(this);
 
   @override
   visitChildren(Visitor v) {}
@@ -669,7 +667,7 @@
     return new TypedefType(this, _getAsTypeArguments(typeParameters));
   }
 
-  accept(TreeVisitor v) {
+  R accept<R>(TreeVisitor<R> v) {
     return v.visitTypedef(this);
   }
 
@@ -753,7 +751,6 @@
 /// use those from its mixed-in type.  However, the IR does not enforce this
 /// rule directly, as doing so can obstruct transformations.  It is possible to
 /// transform a mixin application to become a regular class, and vice versa.
-@coq
 class Class extends NamedNode implements Annotatable, FileUriNode {
   /// Start offset of the class in the source file it comes from.
   ///
@@ -776,7 +773,6 @@
   ///
   /// This defaults to an immutable empty list. Use [addAnnotation] to add
   /// annotations if needed.
-  @nocoq
   List<Expression> annotations = const <Expression>[];
 
   /// Name of the class.
@@ -786,7 +782,6 @@
   /// The name may contain characters that are not valid in a Dart identifier,
   /// in particular, the symbol '&' is used in class names generated for mixin
   /// applications.
-  @coq
   String name;
 
   // Must match serialized bit positions.
@@ -1040,8 +1035,8 @@
     node.parent = this;
   }
 
-  accept(TreeVisitor v) => v.visitClass(this);
-  acceptReference(Visitor v) => v.visitClassReference(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitClass(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitClassReference(this);
 
   /// If true, the class is part of an external library, that is, it is defined
   /// in another build unit.  Only a subset of its members are present.
@@ -1059,18 +1054,15 @@
     return new Supertype(this, _getAsTypeArguments(typeParameters));
   }
 
-  @nocoq
   InterfaceType _rawType;
   InterfaceType get rawType => _rawType ??= new InterfaceType(this);
 
-  @nocoq
   InterfaceType _thisType;
   InterfaceType get thisType {
     return _thisType ??=
         new InterfaceType(this, _getAsTypeArguments(typeParameters));
   }
 
-  @nocoq
   InterfaceType _bottomType;
   InterfaceType get bottomType {
     return _bottomType ??= new InterfaceType(this,
@@ -1155,22 +1147,44 @@
       Reference reference})
       : this.typeParameters = typeParameters ?? <TypeParameter>[],
         this.members = members ?? <ExtensionMemberDescriptor>[],
-        super(reference);
+        super(reference) {
+    setParents(this.typeParameters, this);
+  }
 
   Library get enclosingLibrary => parent;
 
   @override
-  accept(TreeVisitor v) => v.visitExtension(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitExtension(this);
 
   @override
-  visitChildren(Visitor v) {}
+  visitChildren(Visitor v) {
+    visitList(typeParameters, v);
+    onType?.accept(v);
+  }
 
   @override
-  transformChildren(Transformer v) => v.visitExtension(this);
+  transformChildren(Transformer v) {
+    transformList(typeParameters, v, this);
+    if (onType != null) {
+      onType = v.visitDartType(onType);
+    }
+  }
+}
+
+enum ExtensionMemberKind {
+  Field,
+  Method,
+  Getter,
+  Setter,
+  Operator,
+  TearOff,
 }
 
 /// Information about an member declaration in an extension.
 class ExtensionMemberDescriptor {
+  static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
+  static const int FlagExternal = 1 << 1;
+
   /// The name of the extension member.
   ///
   /// The name of the generated top-level member is mangled to ensure
@@ -1178,10 +1192,7 @@
   /// extension itself.
   Name name;
 
-  /// [ProcedureKind] kind of the original member, if the extension is a
-  /// [Procedure] and `null` otherwise.
-  ///
-  /// This can be either `Method`, `Getter`, `Setter`, or `Operator`.
+  /// [ExtensionMemberKind] kind of the original member.
   ///
   /// An extension method is converted into a regular top-level method. For
   /// instance:
@@ -1201,7 +1212,7 @@
   /// where `B|get#bar` is the synthesized name of the top-level method and
   /// `#this` is the synthesized parameter that holds represents `this`.
   ///
-  ProcedureKind kind;
+  ExtensionMemberKind kind;
 
   int flags = 0;
 
@@ -1219,21 +1230,17 @@
   }
 
   /// Return `true` if the extension method was declared as `static`.
-  bool get isStatic => flags & Procedure.FlagStatic != 0;
+  bool get isStatic => flags & FlagStatic != 0;
 
   /// Return `true` if the extension method was declared as `external`.
-  bool get isExternal => flags & Procedure.FlagExternal != 0;
+  bool get isExternal => flags & FlagExternal != 0;
 
   void set isStatic(bool value) {
-    flags = value
-        ? (flags | Procedure.FlagStatic)
-        : (flags & ~Procedure.FlagStatic);
+    flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
   }
 
   void set isExternal(bool value) {
-    flags = value
-        ? (flags | Procedure.FlagExternal)
-        : (flags & ~Procedure.FlagExternal);
+    flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
   }
 }
 
@@ -1241,7 +1248,6 @@
 //                            MEMBERS
 // ------------------------------------------------------------------------
 
-@coq
 abstract class Member extends NamedNode implements Annotatable, FileUriNode {
   /// End offset in the source file it comes from.
   ///
@@ -1254,7 +1260,6 @@
   ///
   /// This defaults to an immutable empty list. Use [addAnnotation] to add
   /// annotations if needed.
-  @nocoq
   List<Expression> annotations = const <Expression>[];
 
   Name name;
@@ -1284,7 +1289,7 @@
   Class get enclosingClass => parent is Class ? parent : null;
   Library get enclosingLibrary => parent is Class ? parent.parent : parent;
 
-  accept(MemberVisitor v);
+  R accept<R>(MemberVisitor<R> v);
   acceptReference(MemberReferenceVisitor v);
 
   /// If true, the member is part of an external library, that is, it is defined
@@ -1494,7 +1499,7 @@
     if (value) throw 'Fields cannot be external';
   }
 
-  accept(MemberVisitor v) => v.visitField(this);
+  R accept<R>(MemberVisitor<R> v) => v.visitField(this);
 
   acceptReference(MemberReferenceVisitor v) => v.visitFieldReference(this);
 
@@ -1509,7 +1514,7 @@
     type = v.visitDartType(type);
     transformList(annotations, v, this);
     if (initializer != null) {
-      initializer = initializer.accept(v);
+      initializer = initializer.accept<TreeNode>(v);
       initializer?.parent = this;
     }
   }
@@ -1593,7 +1598,7 @@
   @override
   bool get isExtensionMember => false;
 
-  accept(MemberVisitor v) => v.visitConstructor(this);
+  R accept<R>(MemberVisitor<R> v) => v.visitConstructor(this);
 
   acceptReference(MemberReferenceVisitor v) =>
       v.visitConstructorReference(this);
@@ -1609,7 +1614,7 @@
     transformList(annotations, v, this);
     transformList(initializers, v, this);
     if (function != null) {
-      function = function.accept(v);
+      function = function.accept<TreeNode>(v);
       function?.parent = this;
     }
   }
@@ -1730,7 +1735,7 @@
     targetReference = getMemberReference(member);
   }
 
-  accept(MemberVisitor v) => v.visitRedirectingFactoryConstructor(this);
+  R accept<R>(MemberVisitor<R> v) => v.visitRedirectingFactoryConstructor(this);
 
   acceptReference(MemberReferenceVisitor v) =>
       v.visitRedirectingFactoryConstructorReference(this);
@@ -1770,7 +1775,6 @@
 /// For index-getters/setters, this is `[]` and `[]=`.
 /// For operators, this is the token for the operator, e.g. `+` or `==`,
 /// except for the unary minus operator, whose name is `unary-`.
-@coq
 class Procedure extends Member {
   /// Start offset of the function in the source file it comes from.
   ///
@@ -1981,7 +1985,7 @@
     forwardingStubInterfaceTargetReference = getMemberReference(target);
   }
 
-  accept(MemberVisitor v) => v.visitProcedure(this);
+  R accept<R>(MemberVisitor<R> v) => v.visitProcedure(this);
 
   acceptReference(MemberReferenceVisitor v) => v.visitProcedureReference(this);
 
@@ -1994,7 +1998,7 @@
   transformChildren(Transformer v) {
     transformList(annotations, v, this);
     if (function != null) {
-      function = function.accept(v);
+      function = function.accept<TreeNode>(v);
       function?.parent = this;
     }
   }
@@ -2032,7 +2036,7 @@
   @informative
   bool isSynthetic = false;
 
-  accept(InitializerVisitor v);
+  R accept<R>(InitializerVisitor<R> v);
 }
 
 /// An initializer with a compile-time error.
@@ -2042,7 +2046,7 @@
 // DESIGN TODO: The frontend should use this in a lot more cases to catch
 // invalid cases.
 class InvalidInitializer extends Initializer {
-  accept(InitializerVisitor v) => v.visitInvalidInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitInvalidInitializer(this);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -2074,7 +2078,7 @@
     fieldReference = field?.reference;
   }
 
-  accept(InitializerVisitor v) => v.visitFieldInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitFieldInitializer(this);
 
   visitChildren(Visitor v) {
     field?.acceptReference(v);
@@ -2083,7 +2087,7 @@
 
   transformChildren(Transformer v) {
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2116,7 +2120,7 @@
     targetReference = getMemberReference(target);
   }
 
-  accept(InitializerVisitor v) => v.visitSuperInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitSuperInitializer(this);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -2125,7 +2129,7 @@
 
   transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -2154,7 +2158,7 @@
     targetReference = getMemberReference(target);
   }
 
-  accept(InitializerVisitor v) => v.visitRedirectingInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitRedirectingInitializer(this);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -2163,7 +2167,7 @@
 
   transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -2180,7 +2184,7 @@
     variable?.parent = this;
   }
 
-  accept(InitializerVisitor v) => v.visitLocalInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitLocalInitializer(this);
 
   visitChildren(Visitor v) {
     variable?.accept(v);
@@ -2188,7 +2192,7 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
   }
@@ -2201,14 +2205,14 @@
     statement.parent = this;
   }
 
-  accept(InitializerVisitor v) => v.visitAssertInitializer(this);
+  R accept<R>(InitializerVisitor<R> v) => v.visitAssertInitializer(this);
 
   visitChildren(Visitor v) {
     statement.accept(v);
   }
 
   transformChildren(Transformer v) {
-    statement = statement.accept(v);
+    statement = statement.accept<TreeNode>(v);
     statement.parent = this;
   }
 }
@@ -2221,7 +2225,6 @@
 ///
 /// This may occur in a procedure, constructor, function expression, or local
 /// function declaration.
-@coq
 class FunctionNode extends TreeNode {
   /// End offset in the source file it comes from. Valid values are from 0 and
   /// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available
@@ -2246,9 +2249,7 @@
 
   List<TypeParameter> typeParameters;
   int requiredParameterCount;
-  @coqsingledef
   List<VariableDeclaration> positionalParameters;
-  @nocoq
   List<VariableDeclaration> namedParameters;
   DartType returnType; // Not null.
   Statement _body;
@@ -2319,7 +2320,7 @@
         requiredParameterCount: requiredParameterCount);
   }
 
-  accept(TreeVisitor v) => v.visitFunctionNode(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitFunctionNode(this);
 
   visitChildren(Visitor v) {
     visitList(typeParameters, v);
@@ -2335,7 +2336,7 @@
     transformList(namedParameters, v, this);
     returnType = v.visitDartType(returnType);
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -2390,7 +2391,6 @@
 //                                EXPRESSIONS
 // ------------------------------------------------------------------------
 
-@coq
 abstract class Expression extends TreeNode {
   /// Returns the static type of the expression.
   ///
@@ -2435,13 +2435,16 @@
     return superclass.rawType;
   }
 
-  accept(ExpressionVisitor v);
-  accept1(ExpressionVisitor1 v, arg);
+  R accept<R>(ExpressionVisitor<R> v);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg);
 }
 
 /// An expression containing compile-time errors.
 ///
 /// Should throw a runtime error when evaluated.
+///
+/// The [fileOffset] of an [InvalidExpression] indicates the location in the
+/// tree where the expression occurs, rather than the location of the error.
 class InvalidExpression extends Expression {
   String message;
 
@@ -2449,18 +2452,17 @@
 
   DartType getStaticType(TypeEnvironment types) => const BottomType();
 
-  accept(ExpressionVisitor v) => v.visitInvalidExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitInvalidExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInvalidExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInvalidExpression(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
 }
 
 /// Read a local variable, a local function, or a function parameter.
-@coq
 class VariableGet extends Expression {
   VariableDeclaration variable;
-  @nocoq
   DartType promotedType; // Null if not promoted.
 
   VariableGet(this.variable, [this.promotedType]);
@@ -2469,8 +2471,9 @@
     return promotedType ?? variable.type;
   }
 
-  accept(ExpressionVisitor v) => v.visitVariableGet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitVariableGet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitVariableGet(this, arg);
 
   visitChildren(Visitor v) {
     promotedType?.accept(v);
@@ -2496,8 +2499,9 @@
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitVariableSet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitVariableSet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitVariableSet(this, arg);
 
   visitChildren(Visitor v) {
     value?.accept(v);
@@ -2505,7 +2509,7 @@
 
   transformChildren(Transformer v) {
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2514,13 +2518,10 @@
 /// Expression of form `x.field`.
 ///
 /// This may invoke a getter, read a field, or tear off a method.
-@coq
 class PropertyGet extends Expression {
   Expression receiver;
-  @coq
   Name name;
 
-  @nocoq
   Reference interfaceTargetReference;
 
   PropertyGet(Expression receiver, Name name, [Member interfaceTarget])
@@ -2555,8 +2556,9 @@
     return const DynamicType();
   }
 
-  accept(ExpressionVisitor v) => v.visitPropertyGet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitPropertyGet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitPropertyGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitPropertyGet(this, arg);
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
@@ -2565,7 +2567,7 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
   }
@@ -2602,8 +2604,9 @@
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitPropertySet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitPropertySet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitPropertySet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitPropertySet(this, arg);
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
@@ -2613,11 +2616,11 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2648,13 +2651,14 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
   }
 
-  accept(ExpressionVisitor v) => v.visitDirectPropertyGet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitDirectPropertyGet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDirectPropertyGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDirectPropertyGet(this, arg);
 
   DartType getStaticType(TypeEnvironment types) {
     Class superclass = target.enclosingClass;
@@ -2695,17 +2699,18 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
 
-  accept(ExpressionVisitor v) => v.visitDirectPropertySet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitDirectPropertySet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDirectPropertySet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDirectPropertySet(this, arg);
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 }
@@ -2742,17 +2747,17 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
 
-  accept(ExpressionVisitor v) => v.visitDirectMethodInvocation(this);
-  accept1(ExpressionVisitor1 v, arg) =>
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDirectMethodInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDirectMethodInvocation(this, arg);
 
   DartType getStaticType(TypeEnvironment types) {
@@ -2799,8 +2804,9 @@
         .substituteType(interfaceTarget.getterType);
   }
 
-  accept(ExpressionVisitor v) => v.visitSuperPropertyGet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSuperPropertyGet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertyGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSuperPropertyGet(this, arg);
 
   visitChildren(Visitor v) {
     name?.accept(v);
@@ -2836,8 +2842,9 @@
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitSuperPropertySet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSuperPropertySet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSuperPropertySet(this, arg);
 
   visitChildren(Visitor v) {
     name?.accept(v);
@@ -2846,7 +2853,7 @@
 
   transformChildren(Transformer v) {
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2869,8 +2876,9 @@
 
   DartType getStaticType(TypeEnvironment types) => target.getterType;
 
-  accept(ExpressionVisitor v) => v.visitStaticGet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitStaticGet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStaticGet(this, arg);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -2902,8 +2910,9 @@
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitStaticSet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitStaticSet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStaticSet(this, arg);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -2912,7 +2921,7 @@
 
   transformChildren(Transformer v) {
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2920,11 +2929,8 @@
 
 /// The arguments to a function call, divided into type arguments,
 /// positional arguments, and named arguments.
-@coq
 class Arguments extends TreeNode {
-  @nocoq
   final List<DartType> types;
-  @coqsingle
   final List<Expression> positional;
   List<NamedExpression> named;
 
@@ -2952,7 +2958,7 @@
             .toList());
   }
 
-  accept(TreeVisitor v) => v.visitArguments(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitArguments(this);
 
   visitChildren(Visitor v) {
     visitList(types, v);
@@ -2976,7 +2982,7 @@
     value?.parent = this;
   }
 
-  accept(TreeVisitor v) => v.visitNamedExpression(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitNamedExpression(this);
 
   visitChildren(Visitor v) {
     value?.accept(v);
@@ -2984,7 +2990,7 @@
 
   transformChildren(Transformer v) {
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -2992,7 +2998,6 @@
 
 /// Common super class for [DirectMethodInvocation], [MethodInvocation],
 /// [SuperMethodInvocation], [StaticInvocation], and [ConstructorInvocation].
-@coq
 abstract class InvocationExpression extends Expression {
   Arguments get arguments;
   set arguments(Arguments value);
@@ -3004,7 +3009,6 @@
 }
 
 /// Expression of form `x.foo(y)`.
-@coq
 class MethodInvocation extends InvocationExpression {
   Expression receiver;
   Name name;
@@ -3068,8 +3072,9 @@
     return const DynamicType();
   }
 
-  accept(ExpressionVisitor v) => v.visitMethodInvocation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitMethodInvocation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitMethodInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitMethodInvocation(this, arg);
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
@@ -3079,11 +3084,11 @@
 
   transformChildren(Transformer v) {
     if (receiver != null) {
-      receiver = receiver.accept(v);
+      receiver = receiver.accept<TreeNode>(v);
       receiver?.parent = this;
     }
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -3124,8 +3129,9 @@
         .substituteType(returnType);
   }
 
-  accept(ExpressionVisitor v) => v.visitSuperMethodInvocation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSuperMethodInvocation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperMethodInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSuperMethodInvocation(this, arg);
 
   visitChildren(Visitor v) {
     name?.accept(v);
@@ -3134,7 +3140,7 @@
 
   transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -3174,8 +3180,9 @@
         .substituteType(target.function.returnType);
   }
 
-  accept(ExpressionVisitor v) => v.visitStaticInvocation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitStaticInvocation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStaticInvocation(this, arg);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -3184,7 +3191,7 @@
 
   transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -3197,10 +3204,8 @@
 // DESIGN TODO: Should we pass type arguments in a separate field
 // `classTypeArguments`? They are quite different from type arguments to
 // generic functions.
-@coq
 class ConstructorInvocation extends InvocationExpression {
   Reference targetReference;
-  @nocoq
   Arguments arguments;
   bool isConst;
 
@@ -3228,8 +3233,9 @@
         : new InterfaceType(target.enclosingClass, arguments.types);
   }
 
-  accept(ExpressionVisitor v) => v.visitConstructorInvocation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitConstructorInvocation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitConstructorInvocation(this, arg);
 
   visitChildren(Visitor v) {
     target?.acceptReference(v);
@@ -3238,7 +3244,7 @@
 
   transformChildren(Transformer v) {
     if (arguments != null) {
-      arguments = arguments.accept(v);
+      arguments = arguments.accept<TreeNode>(v);
       arguments?.parent = this;
     }
   }
@@ -3265,8 +3271,9 @@
         .substituteType(type.withoutTypeParameters);
   }
 
-  accept(ExpressionVisitor v) => v.visitInstantiation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitInstantiation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstantiation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstantiation(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -3275,7 +3282,7 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
     transformTypeList(typeArguments, v);
@@ -3295,8 +3302,8 @@
 
   DartType getStaticType(TypeEnvironment types) => types.boolType;
 
-  accept(ExpressionVisitor v) => v.visitNot(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitNot(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);
 
   visitChildren(Visitor v) {
     operand?.accept(v);
@@ -3304,7 +3311,7 @@
 
   transformChildren(Transformer v) {
     if (operand != null) {
-      operand = operand.accept(v);
+      operand = operand.accept<TreeNode>(v);
       operand?.parent = this;
     }
   }
@@ -3323,8 +3330,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.boolType;
 
-  accept(ExpressionVisitor v) => v.visitLogicalExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitLogicalExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitLogicalExpression(this, arg);
 
   visitChildren(Visitor v) {
     left?.accept(v);
@@ -3333,11 +3341,11 @@
 
   transformChildren(Transformer v) {
     if (left != null) {
-      left = left.accept(v);
+      left = left.accept<TreeNode>(v);
       left?.parent = this;
     }
     if (right != null) {
-      right = right.accept(v);
+      right = right.accept<TreeNode>(v);
       right?.parent = this;
     }
   }
@@ -3361,8 +3369,9 @@
 
   DartType getStaticType(TypeEnvironment types) => staticType;
 
-  accept(ExpressionVisitor v) => v.visitConditionalExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitConditionalExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitConditionalExpression(this, arg);
 
   visitChildren(Visitor v) {
     condition?.accept(v);
@@ -3373,15 +3382,15 @@
 
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept(v);
+      then = then.accept<TreeNode>(v);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept(v);
+      otherwise = otherwise.accept<TreeNode>(v);
       otherwise?.parent = this;
     }
     if (staticType != null) {
@@ -3406,8 +3415,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.stringType;
 
-  accept(ExpressionVisitor v) => v.visitStringConcatenation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitStringConcatenation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStringConcatenation(this, arg);
 
   visitChildren(Visitor v) {
     visitList(expressions, v);
@@ -3437,8 +3447,9 @@
     return types.literalListType(typeArgument);
   }
 
-  accept(ExpressionVisitor v) => v.visitListConcatenation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitListConcatenation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitListConcatenation(this, arg);
 
   visitChildren(Visitor v) {
     typeArgument?.accept(v);
@@ -3473,8 +3484,9 @@
     return types.literalSetType(typeArgument);
   }
 
-  accept(ExpressionVisitor v) => v.visitSetConcatenation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSetConcatenation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSetConcatenation(this, arg);
 
   visitChildren(Visitor v) {
     typeArgument?.accept(v);
@@ -3512,8 +3524,9 @@
     return types.literalMapType(keyType, valueType);
   }
 
-  accept(ExpressionVisitor v) => v.visitMapConcatenation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitMapConcatenation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitMapConcatenation(this, arg);
 
   visitChildren(Visitor v) {
     keyType?.accept(v);
@@ -3530,7 +3543,7 @@
 
 /// Create an instance directly from the field values.
 ///
-/// This expression arises from const constructor calls when one or more field
+/// These expressions arise from const constructor calls when one or more field
 /// initializing expressions, field initializers, assert initializers or unused
 /// arguments contain unevaluated expressions. They only ever occur within
 /// unevaluated constants in constant expressions.
@@ -3552,8 +3565,9 @@
         : new InterfaceType(classNode, typeArguments);
   }
 
-  accept(ExpressionVisitor v) => v.visitInstanceCreation(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitInstanceCreation(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitInstanceCreation(this, arg);
 
   visitChildren(Visitor v) {
     classReference.asClass.acceptReference(v);
@@ -3570,7 +3584,7 @@
 
   transformChildren(Transformer v) {
     fieldValues.forEach((Reference fieldRef, Expression value) {
-      Expression transformed = value.accept(v);
+      Expression transformed = value.accept<TreeNode>(v);
       if (transformed != null && !identical(value, transformed)) {
         fieldValues[fieldRef] = transformed;
         transformed.parent = this;
@@ -3581,6 +3595,43 @@
   }
 }
 
+/// A marker indicating that a subexpression originates in a different source
+/// file than the surrounding context.
+///
+/// These expressions arise from inlining of const variables during constant
+/// evaluation. They only ever occur within unevaluated constants in constant
+/// expressions.
+class FileUriExpression extends Expression implements FileUriNode {
+  /// The URI of the source file in which the subexpression is located.
+  /// Can be different from the file containing the [FileUriExpression].
+  Uri fileUri;
+
+  Expression expression;
+
+  FileUriExpression(this.expression, this.fileUri) {
+    expression.parent = this;
+  }
+
+  DartType getStaticType(TypeEnvironment types) =>
+      expression.getStaticType(types);
+
+  R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitFileUriExpression(this, arg);
+
+  visitChildren(Visitor v) {
+    expression.accept(v);
+  }
+
+  transformChildren(Transformer v) {
+    expression = expression.accept<TreeNode>(v)..parent = this;
+  }
+
+  Location _getLocationInEnclosingFile(int offset) {
+    return _getLocationInComponent(enclosingComponent, fileUri, offset);
+  }
+}
+
 /// Expression of form `x is T`.
 class IsExpression extends Expression {
   Expression operand;
@@ -3592,8 +3643,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.boolType;
 
-  accept(ExpressionVisitor v) => v.visitIsExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitIsExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitIsExpression(this, arg);
 
   visitChildren(Visitor v) {
     operand?.accept(v);
@@ -3602,7 +3654,7 @@
 
   transformChildren(Transformer v) {
     if (operand != null) {
-      operand = operand.accept(v);
+      operand = operand.accept<TreeNode>(v);
       operand?.parent = this;
     }
     type = v.visitDartType(type);
@@ -3634,8 +3686,9 @@
 
   DartType getStaticType(TypeEnvironment types) => type;
 
-  accept(ExpressionVisitor v) => v.visitAsExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitAsExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitAsExpression(this, arg);
 
   visitChildren(Visitor v) {
     operand?.accept(v);
@@ -3644,7 +3697,7 @@
 
   transformChildren(Transformer v) {
     if (operand != null) {
-      operand = operand.accept(v);
+      operand = operand.accept<TreeNode>(v);
       operand?.parent = this;
     }
     type = v.visitDartType(type);
@@ -3666,8 +3719,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.stringType;
 
-  accept(ExpressionVisitor v) => v.visitStringLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitStringLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitStringLiteral(this, arg);
 }
 
 class IntLiteral extends BasicLiteral {
@@ -3681,8 +3735,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.intType;
 
-  accept(ExpressionVisitor v) => v.visitIntLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitIntLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitIntLiteral(this, arg);
 }
 
 class DoubleLiteral extends BasicLiteral {
@@ -3692,8 +3747,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.doubleType;
 
-  accept(ExpressionVisitor v) => v.visitDoubleLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitDoubleLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitDoubleLiteral(this, arg);
 }
 
 class BoolLiteral extends BasicLiteral {
@@ -3703,8 +3759,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.boolType;
 
-  accept(ExpressionVisitor v) => v.visitBoolLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitBoolLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitBoolLiteral(this, arg);
 }
 
 class NullLiteral extends BasicLiteral {
@@ -3712,8 +3769,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.nullType;
 
-  accept(ExpressionVisitor v) => v.visitNullLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitNullLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitNullLiteral(this, arg);
 }
 
 class SymbolLiteral extends Expression {
@@ -3723,8 +3781,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.symbolType;
 
-  accept(ExpressionVisitor v) => v.visitSymbolLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSymbolLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSymbolLiteral(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -3737,8 +3796,9 @@
 
   DartType getStaticType(TypeEnvironment types) => types.typeType;
 
-  accept(ExpressionVisitor v) => v.visitTypeLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitTypeLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitTypeLiteral(this, arg);
 
   visitChildren(Visitor v) {
     type?.accept(v);
@@ -3752,8 +3812,9 @@
 class ThisExpression extends Expression {
   DartType getStaticType(TypeEnvironment types) => types.thisType;
 
-  accept(ExpressionVisitor v) => v.visitThisExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitThisExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitThisExpression(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -3762,8 +3823,9 @@
 class Rethrow extends Expression {
   DartType getStaticType(TypeEnvironment types) => const BottomType();
 
-  accept(ExpressionVisitor v) => v.visitRethrow(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitRethrow(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitRethrow(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -3778,8 +3840,8 @@
 
   DartType getStaticType(TypeEnvironment types) => const BottomType();
 
-  accept(ExpressionVisitor v) => v.visitThrow(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitThrow(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -3787,7 +3849,7 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
@@ -3808,8 +3870,9 @@
     return types.literalListType(typeArgument);
   }
 
-  accept(ExpressionVisitor v) => v.visitListLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitListLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitListLiteral(this, arg);
 
   visitChildren(Visitor v) {
     typeArgument?.accept(v);
@@ -3837,8 +3900,9 @@
     return types.literalSetType(typeArgument);
   }
 
-  accept(ExpressionVisitor v) => v.visitSetLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitSetLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitSetLiteral(this, arg);
 
   visitChildren(Visitor v) {
     typeArgument?.accept(v);
@@ -3870,8 +3934,9 @@
     return types.literalMapType(keyType, valueType);
   }
 
-  accept(ExpressionVisitor v) => v.visitMapLiteral(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitMapLiteral(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitMapLiteral(this, arg);
 
   visitChildren(Visitor v) {
     keyType?.accept(v);
@@ -3895,7 +3960,7 @@
     value?.parent = this;
   }
 
-  accept(TreeVisitor v) => v.visitMapEntry(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitMapEntry(this);
 
   visitChildren(Visitor v) {
     key?.accept(v);
@@ -3904,11 +3969,11 @@
 
   transformChildren(Transformer v) {
     if (key != null) {
-      key = key.accept(v);
+      key = key.accept<TreeNode>(v);
       key?.parent = this;
     }
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -3926,8 +3991,9 @@
     return types.unfutureType(operand.getStaticType(types));
   }
 
-  accept(ExpressionVisitor v) => v.visitAwaitExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitAwaitExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitAwaitExpression(this, arg);
 
   visitChildren(Visitor v) {
     operand?.accept(v);
@@ -3935,7 +4001,7 @@
 
   transformChildren(Transformer v) {
     if (operand != null) {
-      operand = operand.accept(v);
+      operand = operand.accept<TreeNode>(v);
       operand?.parent = this;
     }
   }
@@ -3958,8 +4024,9 @@
 
   DartType getStaticType(TypeEnvironment types) => function.functionType;
 
-  accept(ExpressionVisitor v) => v.visitFunctionExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitFunctionExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitFunctionExpression(this, arg);
 
   visitChildren(Visitor v) {
     function?.accept(v);
@@ -3967,7 +4034,7 @@
 
   transformChildren(Transformer v) {
     if (function != null) {
-      function = function.accept(v);
+      function = function.accept<TreeNode>(v);
       function?.parent = this;
     }
   }
@@ -3983,8 +4050,9 @@
 
   DartType getStaticType(TypeEnvironment types) => type;
 
-  accept(ExpressionVisitor v) => v.visitConstantExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitConstantExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitConstantExpression(this, arg);
 
   visitChildren(Visitor v) {
     constant?.acceptReference(v);
@@ -4009,8 +4077,8 @@
 
   DartType getStaticType(TypeEnvironment types) => body.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitLet(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitLet(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);
 
   visitChildren(Visitor v) {
     variable?.accept(v);
@@ -4019,11 +4087,11 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4040,8 +4108,9 @@
 
   DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
 
-  accept(ExpressionVisitor v) => v.visitBlockExpression(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitBlockExpression(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitBlockExpression(this, arg);
 
   visitChildren(Visitor v) {
     body?.accept(v);
@@ -4050,11 +4119,11 @@
 
   transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     if (value != null) {
-      value = value.accept(v);
+      value = value.accept<TreeNode>(v);
       value?.parent = this;
     }
   }
@@ -4082,8 +4151,9 @@
     return types.futureType(const DynamicType());
   }
 
-  accept(ExpressionVisitor v) => v.visitLoadLibrary(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitLoadLibrary(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitLoadLibrary(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -4100,8 +4170,9 @@
     return types.objectType;
   }
 
-  accept(ExpressionVisitor v) => v.visitCheckLibraryIsLoaded(this);
-  accept1(ExpressionVisitor1 v, arg) => v.visitCheckLibraryIsLoaded(this, arg);
+  R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitCheckLibraryIsLoaded(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -4111,13 +4182,11 @@
 //                              STATEMENTS
 // ------------------------------------------------------------------------
 
-@coq
 abstract class Statement extends TreeNode {
-  accept(StatementVisitor v);
-  accept1(StatementVisitor1 v, arg);
+  R accept<R>(StatementVisitor<R> v);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg);
 }
 
-@coq
 class ExpressionStatement extends Statement {
   Expression expression;
 
@@ -4125,8 +4194,9 @@
     expression?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitExpressionStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitExpressionStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitExpressionStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitExpressionStatement(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -4134,13 +4204,12 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
 }
 
-@coq
 class Block extends Statement {
   final List<Statement> statements;
 
@@ -4153,8 +4222,8 @@
     setParents(statements, this);
   }
 
-  accept(StatementVisitor v) => v.visitBlock(this);
-  accept1(StatementVisitor1 v, arg) => v.visitBlock(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitBlock(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) => v.visitBlock(this, arg);
 
   visitChildren(Visitor v) {
     visitList(statements, v);
@@ -4187,8 +4256,9 @@
     setParents(statements, this);
   }
 
-  accept(StatementVisitor v) => v.visitAssertBlock(this);
-  accept1(StatementVisitor1 v, arg) => v.visitAssertBlock(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitAssertBlock(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitAssertBlock(this, arg);
 
   transformChildren(Transformer v) {
     transformList(statements, v, this);
@@ -4205,8 +4275,9 @@
 }
 
 class EmptyStatement extends Statement {
-  accept(StatementVisitor v) => v.visitEmptyStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitEmptyStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitEmptyStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitEmptyStatement(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -4224,8 +4295,9 @@
     message?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitAssertStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitAssertStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitAssertStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitAssertStatement(this, arg);
 
   visitChildren(Visitor v) {
     condition?.accept(v);
@@ -4234,11 +4306,11 @@
 
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (message != null) {
-      message = message.accept(v);
+      message = message.accept<TreeNode>(v);
       message?.parent = this;
     }
   }
@@ -4256,8 +4328,9 @@
     body?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitLabeledStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitLabeledStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitLabeledStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitLabeledStatement(this, arg);
 
   visitChildren(Visitor v) {
     body?.accept(v);
@@ -4265,7 +4338,7 @@
 
   transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4296,8 +4369,9 @@
 
   BreakStatement(this.target);
 
-  accept(StatementVisitor v) => v.visitBreakStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitBreakStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitBreakStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitBreakStatement(this, arg);
 
   visitChildren(Visitor v) {}
   transformChildren(Transformer v) {}
@@ -4312,8 +4386,9 @@
     body?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitWhileStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitWhileStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitWhileStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitWhileStatement(this, arg);
 
   visitChildren(Visitor v) {
     condition?.accept(v);
@@ -4322,11 +4397,11 @@
 
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4341,8 +4416,9 @@
     condition?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitDoStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitDoStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitDoStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitDoStatement(this, arg);
 
   visitChildren(Visitor v) {
     body?.accept(v);
@@ -4351,11 +4427,11 @@
 
   transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
   }
@@ -4374,8 +4450,9 @@
     body?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitForStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitForStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitForStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitForStatement(this, arg);
 
   visitChildren(Visitor v) {
     visitList(variables, v);
@@ -4387,12 +4464,12 @@
   transformChildren(Transformer v) {
     transformList(variables, v, this);
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     transformList(updates, v, this);
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4417,8 +4494,9 @@
     body?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitForInStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitForInStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitForInStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitForInStatement(this, arg);
 
   visitChildren(Visitor v) {
     variable?.accept(v);
@@ -4428,15 +4506,15 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
     if (iterable != null) {
-      iterable = iterable.accept(v);
+      iterable = iterable.accept<TreeNode>(v);
       iterable?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4455,8 +4533,9 @@
     setParents(cases, this);
   }
 
-  accept(StatementVisitor v) => v.visitSwitchStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitSwitchStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitSwitchStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitSwitchStatement(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -4465,7 +4544,7 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
     transformList(cases, v, this);
@@ -4500,7 +4579,7 @@
         body = null,
         isDefault = false;
 
-  accept(TreeVisitor v) => v.visitSwitchCase(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitSwitchCase(this);
 
   visitChildren(Visitor v) {
     visitList(expressions, v);
@@ -4510,7 +4589,7 @@
   transformChildren(Transformer v) {
     transformList(expressions, v, this);
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4522,8 +4601,8 @@
 
   ContinueSwitchStatement(this.target);
 
-  accept(StatementVisitor v) => v.visitContinueSwitchStatement(this);
-  accept1(StatementVisitor1 v, arg) =>
+  R accept<R>(StatementVisitor<R> v) => v.visitContinueSwitchStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
       v.visitContinueSwitchStatement(this, arg);
 
   visitChildren(Visitor v) {}
@@ -4541,8 +4620,9 @@
     otherwise?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitIfStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitIfStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitIfStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitIfStatement(this, arg);
 
   visitChildren(Visitor v) {
     condition?.accept(v);
@@ -4552,21 +4632,20 @@
 
   transformChildren(Transformer v) {
     if (condition != null) {
-      condition = condition.accept(v);
+      condition = condition.accept<TreeNode>(v);
       condition?.parent = this;
     }
     if (then != null) {
-      then = then.accept(v);
+      then = then.accept<TreeNode>(v);
       then?.parent = this;
     }
     if (otherwise != null) {
-      otherwise = otherwise.accept(v);
+      otherwise = otherwise.accept<TreeNode>(v);
       otherwise?.parent = this;
     }
   }
 }
 
-@coq
 class ReturnStatement extends Statement {
   Expression expression; // May be null.
 
@@ -4574,8 +4653,9 @@
     expression?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitReturnStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitReturnStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitReturnStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitReturnStatement(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -4583,7 +4663,7 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
@@ -4599,8 +4679,9 @@
     setParents(catches, this);
   }
 
-  accept(StatementVisitor v) => v.visitTryCatch(this);
-  accept1(StatementVisitor1 v, arg) => v.visitTryCatch(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitTryCatch(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitTryCatch(this, arg);
 
   visitChildren(Visitor v) {
     body?.accept(v);
@@ -4609,7 +4690,7 @@
 
   transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     transformList(catches, v, this);
@@ -4630,7 +4711,7 @@
     body?.parent = this;
   }
 
-  accept(TreeVisitor v) => v.visitCatch(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitCatch(this);
 
   visitChildren(Visitor v) {
     guard?.accept(v);
@@ -4642,15 +4723,15 @@
   transformChildren(Transformer v) {
     guard = v.visitDartType(guard);
     if (exception != null) {
-      exception = exception.accept(v);
+      exception = exception.accept<TreeNode>(v);
       exception?.parent = this;
     }
     if (stackTrace != null) {
-      stackTrace = stackTrace.accept(v);
+      stackTrace = stackTrace.accept<TreeNode>(v);
       stackTrace?.parent = this;
     }
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
   }
@@ -4665,8 +4746,9 @@
     finalizer?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitTryFinally(this);
-  accept1(StatementVisitor1 v, arg) => v.visitTryFinally(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitTryFinally(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitTryFinally(this, arg);
 
   visitChildren(Visitor v) {
     body?.accept(v);
@@ -4675,11 +4757,11 @@
 
   transformChildren(Transformer v) {
     if (body != null) {
-      body = body.accept(v);
+      body = body.accept<TreeNode>(v);
       body?.parent = this;
     }
     if (finalizer != null) {
-      finalizer = finalizer.accept(v);
+      finalizer = finalizer.accept<TreeNode>(v);
       finalizer?.parent = this;
     }
   }
@@ -4713,8 +4795,9 @@
     flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
   }
 
-  accept(StatementVisitor v) => v.visitYieldStatement(this);
-  accept1(StatementVisitor1 v, arg) => v.visitYieldStatement(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitYieldStatement(this, arg);
 
   visitChildren(Visitor v) {
     expression?.accept(v);
@@ -4722,7 +4805,7 @@
 
   transformChildren(Transformer v) {
     if (expression != null) {
-      expression = expression.accept(v);
+      expression = expression.accept<TreeNode>(v);
       expression?.parent = this;
     }
   }
@@ -4736,7 +4819,6 @@
 /// When this occurs as a statement, it must be a direct child of a [Block].
 //
 // DESIGN TODO: Should we remove the 'final' modifier from variables?
-@coqref
 class VariableDeclaration extends Statement {
   /// Offset of the equals sign in the source file it comes from.
   ///
@@ -4767,7 +4849,6 @@
   /// For parameters, this is the default value.
   ///
   /// Should be null in other cases.
-  @coqopt
   Expression initializer; // May be null.
 
   VariableDeclaration(this.name,
@@ -4889,8 +4970,9 @@
     annotations.add(annotation..parent = this);
   }
 
-  accept(StatementVisitor v) => v.visitVariableDeclaration(this);
-  accept1(StatementVisitor1 v, arg) => v.visitVariableDeclaration(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitVariableDeclaration(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitVariableDeclaration(this, arg);
 
   visitChildren(Visitor v) {
     visitList(annotations, v);
@@ -4902,7 +4984,7 @@
     transformList(annotations, v, this);
     type = v.visitDartType(type);
     if (initializer != null) {
-      initializer = initializer.accept(v);
+      initializer = initializer.accept<TreeNode>(v);
       initializer?.parent = this;
     }
   }
@@ -4924,8 +5006,9 @@
     function?.parent = this;
   }
 
-  accept(StatementVisitor v) => v.visitFunctionDeclaration(this);
-  accept1(StatementVisitor1 v, arg) => v.visitFunctionDeclaration(this, arg);
+  R accept<R>(StatementVisitor<R> v) => v.visitFunctionDeclaration(this);
+  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+      v.visitFunctionDeclaration(this, arg);
 
   visitChildren(Visitor v) {
     variable?.accept(v);
@@ -4934,11 +5017,11 @@
 
   transformChildren(Transformer v) {
     if (variable != null) {
-      variable = variable.accept(v);
+      variable = variable.accept<TreeNode>(v);
       variable?.parent = this;
     }
     if (function != null) {
-      function = function.accept(v);
+      function = function.accept<TreeNode>(v);
       function?.parent = this;
     }
   }
@@ -4958,14 +5041,10 @@
 ///
 /// The [toString] method returns a human-readable string that includes the
 /// library name for private names; uniqueness is not guaranteed.
-@coq
 abstract class Name implements Node {
   final int hashCode;
-  @coq
   final String name;
-  @nocoq
   Reference get libraryName;
-  @nocoq
   Library get library;
   bool get isPrivate;
 
@@ -4989,7 +5068,7 @@
     return other is Name && name == other.name && library == other.library;
   }
 
-  accept(Visitor v) => v.visitName(this);
+  R accept<R>(Visitor<R> v) => v.visitName(this);
 
   visitChildren(Visitor v) {
     // DESIGN TODO: Should we visit the library as a library reference?
@@ -5075,12 +5154,11 @@
 ///
 /// The `==` operator on [DartType]s compare based on type equality, not
 /// object identity.
-@coq
 abstract class DartType extends Node {
   const DartType();
 
-  accept(DartTypeVisitor v);
-  accept1(DartTypeVisitor1 v, arg);
+  R accept<R>(DartTypeVisitor<R> v);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg);
 
   bool operator ==(Object other);
 
@@ -5106,13 +5184,14 @@
 
   const InvalidType();
 
-  accept(DartTypeVisitor v) => v.visitInvalidType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitInvalidType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitInvalidType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitInvalidType(this, arg);
   visitChildren(Visitor v) {}
 
   bool operator ==(Object other) => other is InvalidType;
 
-  Nullability get nullability => throw "InvalidType doesn't have nullabiliity";
+  Nullability get nullability => throw "InvalidType doesn't have nullability";
 }
 
 class DynamicType extends DartType {
@@ -5120,8 +5199,9 @@
 
   const DynamicType();
 
-  accept(DartTypeVisitor v) => v.visitDynamicType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitDynamicType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitDynamicType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitDynamicType(this, arg);
   visitChildren(Visitor v) {}
 
   bool operator ==(Object other) => other is DynamicType;
@@ -5134,8 +5214,9 @@
 
   const VoidType();
 
-  accept(DartTypeVisitor v) => v.visitVoidType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitVoidType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitVoidType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitVoidType(this, arg);
   visitChildren(Visitor v) {}
 
   bool operator ==(Object other) => other is VoidType;
@@ -5148,8 +5229,9 @@
 
   const BottomType();
 
-  accept(DartTypeVisitor v) => v.visitBottomType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitBottomType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitBottomType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitBottomType(this, arg);
   visitChildren(Visitor v) {}
 
   bool operator ==(Object other) => other is BottomType;
@@ -5157,13 +5239,11 @@
   Nullability get nullability => Nullability.nonNullable;
 }
 
-@coq
 class InterfaceType extends DartType {
   Reference className;
 
   final Nullability nullability;
 
-  @nocoq
   final List<DartType> typeArguments;
 
   /// The [typeArguments] list must not be modified after this call. If the
@@ -5189,8 +5269,9 @@
     }
   }
 
-  accept(DartTypeVisitor v) => v.visitInterfaceType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitInterfaceType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitInterfaceType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitInterfaceType(this, arg);
 
   visitChildren(Visitor v) {
     classNode.acceptReference(v);
@@ -5221,11 +5302,9 @@
 }
 
 /// A possibly generic function type.
-@coq
 class FunctionType extends DartType {
   final List<TypeParameter> typeParameters;
   final int requiredParameterCount;
-  @coqsingle
   final List<DartType> positionalParameters;
   final List<NamedType> namedParameters; // Must be sorted.
   final Nullability nullability;
@@ -5246,13 +5325,13 @@
         this.requiredParameterCount =
             requiredParameterCount ?? positionalParameters.length;
 
-  @nocoq
   Reference get typedefReference => typedefType?.typedefReference;
 
   Typedef get typedef => typedefReference?.asTypedef;
 
-  accept(DartTypeVisitor v) => v.visitFunctionType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitFunctionType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitFunctionType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitFunctionType(this, arg);
 
   visitChildren(Visitor v) {
     visitList(typeParameters, v);
@@ -5372,8 +5451,9 @@
 
   Typedef get typedefNode => typedefReference.asTypedef;
 
-  accept(DartTypeVisitor v) => v.visitTypedefType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitTypedefType(this, arg);
+  R accept<R>(DartTypeVisitor<R> v) => v.visitTypedefType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitTypedefType(this, arg);
 
   visitChildren(Visitor v) {
     visitList(typeArguments, v);
@@ -5436,7 +5516,7 @@
 
   int compareTo(NamedType other) => name.compareTo(other.name);
 
-  accept(Visitor v) => v.visitNamedType(this);
+  R accept<R>(Visitor<R> v) => v.visitNamedType(this);
 
   void visitChildren(Visitor v) {
     type.accept(v);
@@ -5458,8 +5538,38 @@
 /// is the same as the [TypeParameter]'s bound.  This allows one to detect
 /// whether the bound has been promoted.
 class TypeParameterType extends DartType {
-  /// Declared by the programmer on the type.
-  final Nullability declaredNullability;
+  /// The nullability declared on the type.
+  ///
+  /// Declarations of type-parameter types can set it to [Nullability.nullable]
+  /// or [Nullability.legacy].  Otherwise, it's computed from the nullability
+  /// of the type parameter bound.
+  Nullability declaredNullability;
+
+  TypeParameter parameter;
+
+  /// An optional promoted bound on the type parameter.
+  ///
+  /// 'null' indicates that the type parameter's bound has not been promoted and
+  /// is therefore the same as the bound of [parameter].
+  DartType promotedBound;
+
+  TypeParameterType(this.parameter,
+      [this.promotedBound, this.declaredNullability = Nullability.legacy]);
+
+  R accept<R>(DartTypeVisitor<R> v) => v.visitTypeParameterType(this);
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+      v.visitTypeParameterType(this, arg);
+
+  visitChildren(Visitor v) {}
+
+  bool operator ==(Object other) {
+    return other is TypeParameterType && parameter == other.parameter;
+  }
+
+  int get hashCode => _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
+
+  /// Returns the bound of the type parameter, accounting for promotions.
+  DartType get bound => promotedBound ?? parameter.bound;
 
   /// Actual nullability of the type, calculated from its parts.
   ///
@@ -5480,35 +5590,25 @@
   ///         }
   ///       }
   ///     }
-  final Nullability nullability;
+  Nullability get nullability =>
+      getNullability(parameter, promotedBound, declaredNullability);
 
-  TypeParameter parameter;
-
-  /// An optional promoted bound on the type parameter.
-  ///
-  /// 'null' indicates that the type parameter's bound has not been promoted and
-  /// is therefore the same as the bound of [parameter].
-  DartType promotedBound;
-
-  TypeParameterType(this.parameter,
-      [this.promotedBound, this.declaredNullability = Nullability.legacy])
-      : this.nullability =
-            getNullability(parameter, promotedBound, declaredNullability);
-
-  accept(DartTypeVisitor v) => v.visitTypeParameterType(this);
-  accept1(DartTypeVisitor1 v, arg) => v.visitTypeParameterType(this, arg);
-
-  visitChildren(Visitor v) {}
-
-  bool operator ==(Object other) {
-    return other is TypeParameterType && parameter == other.parameter;
+  static Nullability computeNullabilityFromBound(TypeParameter typeParameter) {
+    // If the bound is nullable, both nullable and non-nullable types can be
+    // passed in for the type parameter, making the corresponding type
+    // parameter types 'neither.'  Otherwise, the nullability matches that of
+    // the bound.
+    DartType bound = typeParameter.bound;
+    if (bound == null) {
+      throw new StateError("Can't compute nullability from absent bound.");
+    }
+    Nullability boundNullability =
+        bound is InvalidType ? Nullability.neither : bound.nullability;
+    return boundNullability == Nullability.nullable
+        ? Nullability.neither
+        : boundNullability;
   }
 
-  int get hashCode => _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
-
-  /// Returns the bound of the type parameter, accounting for promotions.
-  DartType get bound => promotedBound ?? parameter.bound;
-
   /// Get nullability of [TypeParameterType] from arguments to its constructor.
   ///
   /// This method is supposed to be used only in the constructor of
@@ -5521,7 +5621,7 @@
     // by nullability.
 
     // If promotedBound isn't null, getNullability returns the nullability of an
-    // instesection of the left-hand side (referred to as LHS below) and the
+    // intersection of the left-hand side (referred to as LHS below) and the
     // right-hand side (referred to as RHS below).  LHS is parameter followed by
     // nullability, and RHS is promotedBound.  That is, getNullability returns
     // the nullability of either T & P or T? & P where T is parameter, P is
@@ -5530,22 +5630,12 @@
 
     Nullability lhsNullability;
 
-    // If the nullability is explicitly nullable, that is, if the type parameter
-    // type is followed by '?' in the code, the nullability of the type is
-    // 'nullable.'
-    if (declaredNullability == Nullability.nullable) {
-      lhsNullability = Nullability.nullable;
+    // If the nullability is declared explicitly, use it as the nullability of
+    // the LHS of the intersection.  Otherwise, compute it from the bound.
+    if (declaredNullability != null) {
+      lhsNullability = declaredNullability;
     } else {
-      // If the bound is nullable, both nullable and non-nullable types can be
-      // passed in for the type parameter, making the corresponding type
-      // parameter types 'neither.'  Otherwise, the nullability matches that of
-      // the bound.
-      DartType bound = parameter.bound ?? const DynamicType();
-      Nullability boundNullability =
-          bound is InvalidType ? Nullability.neither : bound.nullability;
-      lhsNullability = boundNullability == Nullability.nullable
-          ? Nullability.neither
-          : boundNullability;
+      lhsNullability = computeNullabilityFromBound(parameter);
     }
     if (promotedBound == null) {
       return lhsNullability;
@@ -5678,7 +5768,7 @@
     annotations.add(annotation..parent = this);
   }
 
-  accept(TreeVisitor v) => v.visitTypeParameter(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitTypeParameter(this);
 
   visitChildren(Visitor v) {
     visitList(annotations, v);
@@ -5712,7 +5802,7 @@
 
   Class get classNode => className.asClass;
 
-  accept(Visitor v) => v.visitSupertype(this);
+  R accept<R>(Visitor<R> v) => v.visitSupertype(this);
 
   visitChildren(Visitor v) {
     classNode.acceptReference(v);
@@ -5759,10 +5849,10 @@
   visitChildren(Visitor v);
 
   /// Calls the `visit*Constant()` method on the visitor [v].
-  accept(ConstantVisitor v);
+  R accept<R>(ConstantVisitor<R> v);
 
   /// Calls the `visit*ConstantReference()` method on the visitor [v].
-  acceptReference(Visitor v);
+  R acceptReference<R>(Visitor<R> v);
 
   /// The Kernel AST will reference [Constant]s via [ConstantExpression]s.  The
   /// constants are not required to be canonicalized, but they have to be deeply
@@ -5795,8 +5885,8 @@
   NullConstant() : super(null);
 
   visitChildren(Visitor v) {}
-  accept(ConstantVisitor v) => v.visitNullConstant(this);
-  acceptReference(Visitor v) => v.visitNullConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitNullConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitNullConstantReference(this);
 
   DartType getType(TypeEnvironment types) => types.nullType;
 }
@@ -5805,8 +5895,8 @@
   BoolConstant(bool value) : super(value);
 
   visitChildren(Visitor v) {}
-  accept(ConstantVisitor v) => v.visitBoolConstant(this);
-  acceptReference(Visitor v) => v.visitBoolConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitBoolConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitBoolConstantReference(this);
 
   DartType getType(TypeEnvironment types) => types.boolType;
 }
@@ -5815,8 +5905,8 @@
   IntConstant(int value) : super(value);
 
   visitChildren(Visitor v) {}
-  accept(ConstantVisitor v) => v.visitIntConstant(this);
-  acceptReference(Visitor v) => v.visitIntConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitIntConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitIntConstantReference(this);
 
   DartType getType(TypeEnvironment types) => types.intType;
 }
@@ -5825,8 +5915,8 @@
   DoubleConstant(double value) : super(value);
 
   visitChildren(Visitor v) {}
-  accept(ConstantVisitor v) => v.visitDoubleConstant(this);
-  acceptReference(Visitor v) => v.visitDoubleConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitDoubleConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitDoubleConstantReference(this);
 
   int get hashCode => value.isNaN ? 199 : super.hashCode;
   bool operator ==(Object other) =>
@@ -5841,8 +5931,8 @@
   }
 
   visitChildren(Visitor v) {}
-  accept(ConstantVisitor v) => v.visitStringConstant(this);
-  acceptReference(Visitor v) => v.visitStringConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitStringConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitStringConstantReference(this);
 
   DartType getType(TypeEnvironment types) => types.stringType;
 }
@@ -5855,8 +5945,8 @@
 
   visitChildren(Visitor v) {}
 
-  accept(ConstantVisitor v) => v.visitSymbolConstant(this);
-  acceptReference(Visitor v) => v.visitSymbolConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitSymbolConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitSymbolConstantReference(this);
 
   String toString() {
     return libraryReference != null
@@ -5891,8 +5981,8 @@
     }
   }
 
-  accept(ConstantVisitor v) => v.visitMapConstant(this);
-  acceptReference(Visitor v) => v.visitMapConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitMapConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitMapConstantReference(this);
 
   String toString() => '${this.runtimeType}<$keyType, $valueType>($entries)';
 
@@ -5939,8 +6029,8 @@
     }
   }
 
-  accept(ConstantVisitor v) => v.visitListConstant(this);
-  acceptReference(Visitor v) => v.visitListConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitListConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitListConstantReference(this);
 
   String toString() => '${this.runtimeType}<$typeArgument>($entries)';
 
@@ -5973,8 +6063,8 @@
     }
   }
 
-  accept(ConstantVisitor v) => v.visitSetConstant(this);
-  acceptReference(Visitor v) => v.visitSetConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitSetConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitSetConstantReference(this);
 
   String toString() => '${this.runtimeType}<$typeArgument>($entries)';
 
@@ -6013,8 +6103,8 @@
     }
   }
 
-  accept(ConstantVisitor v) => v.visitInstanceConstant(this);
-  acceptReference(Visitor v) => v.visitInstanceConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitInstanceConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitInstanceConstantReference(this);
 
   String toString() {
     final sb = new StringBuffer();
@@ -6063,8 +6153,9 @@
     visitList(types, v);
   }
 
-  accept(ConstantVisitor v) => v.visitPartialInstantiationConstant(this);
-  acceptReference(Visitor v) =>
+  R accept<R>(ConstantVisitor<R> v) =>
+      v.visitPartialInstantiationConstant(this);
+  R acceptReference<R>(Visitor<R> v) =>
       v.visitPartialInstantiationConstantReference(this);
 
   String toString() {
@@ -6106,17 +6197,18 @@
     procedureReference.asProcedure.acceptReference(v);
   }
 
-  accept(ConstantVisitor v) => v.visitTearOffConstant(this);
-  acceptReference(Visitor v) => v.visitTearOffConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitTearOffConstant(this);
+  R acceptReference<R>(Visitor<R> v) => v.visitTearOffConstantReference(this);
 
   String toString() {
     return '${runtimeType}(${procedure})';
   }
 
-  int get hashCode => procedure.hashCode;
+  int get hashCode => procedureReference.hashCode;
 
   bool operator ==(Object other) {
-    return other is TearOffConstant && other.procedure == procedure;
+    return other is TearOffConstant &&
+        other.procedureReference == procedureReference;
   }
 
   FunctionType getType(TypeEnvironment types) =>
@@ -6132,8 +6224,9 @@
     type.accept(v);
   }
 
-  accept(ConstantVisitor v) => v.visitTypeLiteralConstant(this);
-  acceptReference(Visitor v) => v.visitTypeLiteralConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitTypeLiteralConstant(this);
+  R acceptReference<R>(Visitor<R> v) =>
+      v.visitTypeLiteralConstantReference(this);
 
   String toString() => '${runtimeType}(${type})';
 
@@ -6157,8 +6250,9 @@
     expression.accept(v);
   }
 
-  accept(ConstantVisitor v) => v.visitUnevaluatedConstant(this);
-  acceptReference(Visitor v) => v.visitUnevaluatedConstantReference(this);
+  R accept<R>(ConstantVisitor<R> v) => v.visitUnevaluatedConstant(this);
+  R acceptReference<R>(Visitor<R> v) =>
+      v.visitUnevaluatedConstantReference(this);
 
   DartType getType(TypeEnvironment types) => expression.getStaticType(types);
 
@@ -6241,7 +6335,7 @@
     mainMethodName = getMemberReference(main);
   }
 
-  accept(TreeVisitor v) => v.visitComponent(this);
+  R accept<R>(TreeVisitor<R> v) => v.visitComponent(this);
 
   visitChildren(Visitor v) {
     visitList(libraries, v);
@@ -6557,6 +6651,18 @@
   return class_.canonicalName;
 }
 
+/// Returns the canonical name of [extension], or throws an exception if the
+/// class has not been assigned a canonical name yet.
+///
+/// Returns `null` if the extension is `null`.
+CanonicalName getCanonicalNameOfExtension(Extension extension) {
+  if (extension == null) return null;
+  if (extension.canonicalName == null) {
+    throw '$extension has no canonical name';
+  }
+  return extension.canonicalName;
+}
+
 /// Returns the canonical name of [library], or throws an exception if the
 /// library has not been assigned a canonical name yet.
 ///
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index a66a437..120d1bb 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -415,6 +415,7 @@
   }
 
   List<int> _indexComponents() {
+    _checkEmptyInput();
     int savedByteOffset = _byteOffset;
     _byteOffset = _bytes.length - 4;
     List<int> index = <int>[];
@@ -431,6 +432,10 @@
     return new List.from(index.reversed);
   }
 
+  void _checkEmptyInput() {
+    if (_bytes.length == 0) throw new StateError("Empty input given.");
+  }
+
   /// Deserializes a kernel component and stores it in [component].
   ///
   /// When linking with a non-empty component, canonical names must have been
@@ -438,6 +443,8 @@
   ///
   /// The input bytes may contain multiple files concatenated.
   void readComponent(Component component, {bool checkCanonicalNames: false}) {
+    _checkEmptyInput();
+
     // Check that we have a .dill file and it has the correct version before we
     // start decoding it.  Otherwise we will fail for cryptic reasons.
     int offset = _byteOffset;
@@ -576,10 +583,10 @@
     result.libraryOffsets = new List<int>(result.libraryCount + 1);
     result.componentFileSizeInBytes = readUint32();
     if (result.componentFileSizeInBytes != componentFileSize) {
-      throw 'Malformed binary: This component file\'s component index indicates that'
-          ' the filesize should be $componentFileSize but other component indexes'
-          ' has indicated that the size should be '
-          '${result.componentFileSizeInBytes}.';
+      throw "Malformed binary: This component file's component index indicates that"
+          " the file size should be $componentFileSize but other component indexes"
+          " has indicated that the size should be "
+          "${result.componentFileSizeInBytes}.";
     }
 
     // Skip to the start of the index.
@@ -873,6 +880,11 @@
       return readClass(classOffsets[index + 1]);
     }, library);
     _byteOffset = classOffsets.last;
+
+    _mergeNamedNodeList(library.extensions, (index) {
+      return readExtension();
+    }, library);
+
     _mergeNamedNodeList(library.fields, (index) => readField(), library);
     _mergeNamedNodeList(library.procedures, (index) {
       _byteOffset = procedureOffsets[index];
@@ -1057,6 +1069,57 @@
     return node;
   }
 
+  Extension readExtension() {
+    int tag = readByte();
+    assert(tag == Tag.Extension);
+
+    CanonicalName canonicalName = readCanonicalNameReference();
+    Reference reference = canonicalName.getReference();
+    Extension node = reference.node;
+    if (alwaysCreateNewNamedNodes) {
+      node = null;
+    }
+    bool shouldWriteData = node == null || _isReadingLibraryImplementation;
+    if (node == null) {
+      node = new Extension(reference: reference);
+    }
+
+    String name = readStringOrNullIfEmpty();
+    assert(() {
+      debugPath.add(node.name ?? 'extension');
+      return true;
+    }());
+
+    Uri fileUri = readUriReference();
+    node.fileOffset = readOffset();
+
+    readAndPushTypeParameterList(node.typeParameters, node);
+    DartType onType = readDartType();
+    typeParameterStack.length = 0;
+
+    if (shouldWriteData) {
+      node.name = name;
+      node.fileUri = fileUri;
+      node.onType = onType;
+    }
+
+    int length = readUInt();
+    for (int i = 0; i < length; i++) {
+      Name name = readName();
+      int kind = readByte();
+      int flags = readByte();
+      CanonicalName canonicalName = readCanonicalNameReference();
+      if (shouldWriteData) {
+        node.members.add(new ExtensionMemberDescriptor(
+            name: name,
+            kind: ExtensionMemberKind.values[kind],
+            member: canonicalName.getReference())
+          ..flags = flags);
+      }
+    }
+    return node;
+  }
+
   int getAndResetTransformerFlags() {
     int flags = _transformerFlags;
     _transformerFlags = 0;
@@ -1601,6 +1664,11 @@
         return new InstanceCreation(classReference, typeArguments, fieldValues,
             asserts, unusedArguments)
           ..fileOffset = offset;
+      case Tag.FileUriExpression:
+        Uri fileUri = readUriReference();
+        int offset = readOffset();
+        return new FileUriExpression(readExpression(), fileUri)
+          ..fileOffset = offset;
       case Tag.IsExpression:
         int offset = readOffset();
         return new IsExpression(readExpression(), readDartType())
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 824c145..ac32edd 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -326,6 +326,15 @@
     }
   }
 
+  void writeExtensionNodeList(List<Extension> nodes) {
+    final len = nodes.length;
+    writeUInt30(len);
+    for (int i = 0; i < len; i++) {
+      final node = nodes[i];
+      writeExtensionNode(node);
+    }
+  }
+
   void writeConstructorNodeList(List<Constructor> nodes) {
     final len = nodes.length;
     writeUInt30(len);
@@ -421,6 +430,13 @@
     node.accept(this);
   }
 
+  void writeExtensionNode(Extension node) {
+    if (_metadataSubsections != null) {
+      _writeNodeMetadata(node);
+    }
+    node.accept(this);
+  }
+
   void writeConstructorNode(Constructor node) {
     if (_metadataSubsections != null) {
       _writeNodeMetadata(node);
@@ -932,6 +948,7 @@
     classOffsets = new List<int>();
     writeClassNodeList(node.classes);
     classOffsets.add(getBufferOffset());
+    writeExtensionNodeList(node.extensions);
     writeFieldNodeList(node.fields);
     procedureOffsets = new List<int>();
     writeProcedureNodeList(node.procedures);
@@ -1553,6 +1570,14 @@
   }
 
   @override
+  void visitFileUriExpression(FileUriExpression node) {
+    writeByte(Tag.FileUriExpression);
+    writeUriReference(node.fileUri);
+    writeOffset(node.fileOffset);
+    writeNode(node.expression);
+  }
+
+  @override
   void visitIsExpression(IsExpression node) {
     writeByte(Tag.IsExpression);
     writeOffset(node.fileOffset);
@@ -2096,8 +2121,29 @@
 
   @override
   void visitExtension(Extension node) {
-    // TODO(johnniwinther): Support serialization of extension nodes.
-    throw new UnsupportedError('serialization of extension nodes');
+    if (node.canonicalName == null) {
+      throw new ArgumentError('Missing canonical name for $node');
+    }
+    writeByte(Tag.Extension);
+    writeNonNullCanonicalNameReference(getCanonicalNameOfExtension(node));
+    writeStringReference(node.name ?? '');
+    writeUriReference(node.fileUri);
+    writeOffset(node.fileOffset);
+
+    enterScope(typeParameters: node.typeParameters);
+    writeNodeList(node.typeParameters);
+    writeDartType(node.onType);
+    leaveScope(typeParameters: node.typeParameters);
+
+    final int len = node.members.length;
+    writeUInt30(len);
+    for (int i = 0; i < len; i++) {
+      final ExtensionMemberDescriptor descriptor = node.members[i];
+      writeName(descriptor.name);
+      writeByte(descriptor.kind.index);
+      writeByte(descriptor.flags);
+      writeNonNullCanonicalNameReference(descriptor.member.canonicalName);
+    }
   }
 
   // ================================================================
@@ -2215,7 +2261,7 @@
 
   @override
   void visitLibraryDependency(LibraryDependency node) {
-    throw new UnsupportedError('serialization of LibraryDependencys');
+    throw new UnsupportedError('serialization of LibraryDependencies');
   }
 
   @override
@@ -2664,7 +2710,7 @@
    * Returns
    *  * Non-negative on success (the new index in [target]).
    *  * -1 when [target] doesn't have enough space. Note that [target] can be
-   *    poluted starting at [index].
+   *    polluted starting at [index].
    *  * -2 on input error, i.e. an unpaired lead or tail surrogate.
    */
   static int writeUtf8(List<int> target, int index, String source,
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 3fcad11..dc93073 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -8,6 +8,7 @@
   static const int Something = 1;
 
   static const int Class = 2;
+  static const int Extension = 115;
 
   static const int FunctionNode = 3;
 
@@ -80,6 +81,7 @@
   static const int ConstMapLiteral = 59;
   static const int SetLiteral = 109;
   static const int ConstSetLiteral = 110;
+  static const int FileUriExpression = 116;
 
   // Statements
   static const int ExpressionStatement = 61;
@@ -117,16 +119,8 @@
   static const int SimpleInterfaceType = 96;
   static const int SimpleFunctionType = 97;
 
-  // References
-  static const int NullReference = 99;
-  static const int ClassReference = 100;
-  static const int MemberReference = 101;
-
   static const int ConstantExpression = 106;
 
-  // Tag is deprecated since version 24.
-  static const int Deprecated_ConstantExpression = 107;
-
   /// 108 is occupied by [RedirectingFactoryConstructor] (member).
   /// 109 is occupied by [SetLiteral] (expression).
   /// 110 is occupied by [ConstSetLiteral] (expression).
@@ -134,6 +128,8 @@
   /// 112 is occupied by [SetConcatenation] (expression).
   /// 113 is occupied by [MapConcatenation] (expression).
   /// 114 is occupied by [InstanceCreation] (expression).
+  /// 115 is occupied by [Extension].
+  /// 116 is occupied by [FileUriExpression] (expression).
 
   static const int SpecializedTagHighBit = 0x80; // 10000000
   static const int SpecializedTagMask = 0xF8; // 11111000
@@ -150,7 +146,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 29;
+  static const int BinaryFormatVersion = 31;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
index 76fd5d8..29aeac4 100644
--- a/pkg/kernel/lib/canonical_name.dart
+++ b/pkg/kernel/lib/canonical_name.dart
@@ -20,6 +20,10 @@
 ///         Canonical name of enclosing library
 ///         Name of class
 ///
+///      Extension:
+///         Canonical name of enclosing library
+///         Name of extension
+///
 ///      Constructor:
 ///         Canonical name of enclosing class or library
 ///         "@constructors"
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 7be58d1..73cd12a 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -41,7 +41,7 @@
   /// [unordered], they are not included.
   Iterable<Class> getOrderedClasses(Iterable<Class> unordered);
 
-  // Returns the instantition of each generic supertype implemented by this
+  // Returns the instantiation of each generic supertype implemented by this
   // class (e.g. getClassAsInstanceOf applied to all superclasses and
   // interfaces).
   List<Supertype> genericSupertypesOf(Class class_);
@@ -377,7 +377,7 @@
   @override
   Member getSingleTargetForInterfaceInvocation(Member interfaceTarget,
       {bool setter: false}) {
-    if (invalidated) throw "This datastructure has been invalidated";
+    if (invalidated) throw "This data structure has been invalidated";
     Name name = interfaceTarget.name;
     Member target = null;
     ClassSet subtypes = getSubtypesOf(interfaceTarget.enclosingClass);
@@ -398,7 +398,7 @@
 
   @override
   ClassSet getSubtypesOf(Class class_) {
-    if (invalidated) throw "This datastructure has been invalidated";
+    if (invalidated) throw "This data structure has been invalidated";
     Set<Class> result = new Set<Class>();
     Uint32List list = _infoMap[class_].subtypeIntervalList;
     for (int i = 0; i < list.length; i += 2) {
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 62b3a7b..e0dc4e7 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -13,7 +13,7 @@
 ///
 /// It is safe to clone members, but cloning a class or library is not
 /// supported.
-class CloneVisitor implements TreeVisitor {
+class CloneVisitor implements TreeVisitor<TreeNode> {
   final Map<VariableDeclaration, VariableDeclaration> variables =
       <VariableDeclaration, VariableDeclaration>{};
   final Map<LabeledStatement, LabeledStatement> labels =
@@ -222,6 +222,10 @@
         node.unusedArguments.map(clone).toList());
   }
 
+  visitFileUriExpression(FileUriExpression node) {
+    return new FileUriExpression(clone(node.expression), _activeFileUri);
+  }
+
   visitIsExpression(IsExpression node) {
     return new IsExpression(clone(node.operand), visitType(node.type));
   }
diff --git a/pkg/kernel/lib/coq_annot.dart b/pkg/kernel/lib/coq_annot.dart
deleted file mode 100644
index 551ce79..0000000
--- a/pkg/kernel/lib/coq_annot.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// Please see the comments in `pkg/kernel/lib/transformations/coq.dart` for more
-// info.
-
-library kernel.coq_annot;
-
-const coq = 1; // field or class
-const coqref = 2; // class only
-const nocoq = 3; // field only
-const coqopt = 4; // field only
-const coqsingle = 5; // treat List<A> as just A
-const coqdef = 6;
-const coqsingledef = 7;
-
-// library only
-class CoqLib {
-  final String destPathRelative;
-  const CoqLib(this.destPathRelative);
-}
-
-// TODO(30609): Since fasta currently throws away annotations on Enums, we use a
-// list to identify which enums to convert.
-//
-// We'll uncomment these enums once the Coq formalization is sufficiently complete.
-var coqEnums = [/*"kernel.ast::ProcedureKind", "kernel.ast::AsyncMarker"*/];
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index a165582..040d266 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -110,7 +110,7 @@
   }
 }
 
-DartType instantiateToBounds(DartType type, Class object) {
+DartType instantiateToBounds(DartType type, Class objectClass) {
   if (type is InterfaceType) {
     for (var typeArgument in type.typeArguments) {
       // If at least one of the arguments is not dynamic, we assume that the
@@ -120,8 +120,8 @@
         return type;
       }
     }
-    return new InterfaceType.byReference(
-        type.className, calculateBounds(type.classNode.typeParameters, object));
+    return new InterfaceType.byReference(type.className,
+        calculateBounds(type.classNode.typeParameters, objectClass));
   }
   if (type is TypedefType) {
     for (var typeArgument in type.typeArguments) {
@@ -130,7 +130,7 @@
       }
     }
     return new TypedefType.byReference(type.typedefReference,
-        calculateBounds(type.typedefNode.typeParameters, object));
+        calculateBounds(type.typedefNode.typeParameters, objectClass));
   }
   return type;
 }
@@ -142,15 +142,16 @@
 /// (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/instantiate-to-bound.md)
 /// of the algorithm for details.
 List<DartType> calculateBounds(
-    List<TypeParameter> typeParameters, Class object) {
+    List<TypeParameter> typeParameters, Class objectClass) {
   List<DartType> bounds = new List<DartType>(typeParameters.length);
   for (int i = 0; i < typeParameters.length; i++) {
     DartType bound = typeParameters[i].bound;
     if (bound == null) {
       bound = const DynamicType();
-    } else if (bound is InterfaceType && bound.classNode == object) {
+    } else if (bound is InterfaceType && bound.classNode == objectClass) {
       DartType defaultType = typeParameters[i].defaultType;
-      if (!(defaultType is InterfaceType && defaultType.classNode == object)) {
+      if (!(defaultType is InterfaceType &&
+          defaultType.classNode == objectClass)) {
         bound = const DynamicType();
       }
     }
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 6b88491..64e3b5b 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -84,7 +84,22 @@
   /// A list of URIs of required libraries, not including dart:core.
   ///
   /// Libraries will be loaded in order.
-  List<String> get extraRequiredLibraries => <String>[];
+  List<String> get extraRequiredLibraries => const <String>[];
+
+  /// A list of URIs of extra required libraries when compiling the platform.
+  ///
+  /// Libraries will be loaded in order after the [extraRequiredLibraries]
+  /// above.
+  ///
+  /// Normally not needed, but can be useful if removing libraries from the
+  /// [extraRequiredLibraries] list so libraries will still be available in the
+  /// platform if having a weird mix of current and not-quite-current as can
+  /// sometimes be the case.
+  List<String> get extraRequiredLibrariesPlatform => const <String>[];
+
+  /// A list of URIs of libraries to be indexed in the CoreTypes index, not
+  /// including dart:_internal, dart:async, dart:core and dart:mirrors.
+  List<String> get extraIndexedLibraries => const <String>[];
 
   /// Additional declared variables implied by this target.
   ///
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index dd19365..ccff048 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -4,6 +4,7 @@
 library kernel.ast_to_text;
 
 import 'dart:core' hide MapEntry;
+import 'dart:core' as core show MapEntry;
 
 import 'dart:convert' show json;
 
@@ -30,8 +31,30 @@
 
   String getName(Constant constant) {
     if (!map.containsKey(constant)) {
-      // Name everything in post-order visit of DAG.
-      constant.visitChildren(this);
+      // When printing a non-fully linked kernel AST (i.e. some [Reference]s
+      // are not bound) to text, we need to avoid dereferencing any
+      // references.
+      //
+      // The normal visitor API causes references to be dereferenced in order
+      // to call the `visit<name>(<name>)` / `visit<name>Reference(<name>)`.
+      //
+      // We therefore handle any subclass of [Constant] which has [Reference]s
+      // specially here.
+      //
+      if (constant is InstanceConstant) {
+        // Avoid visiting `InstanceConstant.classReference`.
+        for (final value in constant.fieldValues.values) {
+          // Name everything in post-order visit of DAG.
+          getName(value);
+        }
+      } else if (constant is TearOffConstant) {
+        // We only care about naming the constants themselves. [TearOffConstant]
+        // has no Constant children.
+        // Avoid visiting `TearOffConstant.procedureReference`.
+      } else {
+        // Name everything in post-order visit of DAG.
+        constant.visitChildren(this);
+      }
     }
     return super.getName(constant);
   }
@@ -39,6 +62,11 @@
   defaultConstantReference(Constant constant) {
     getName(constant);
   }
+
+  defaultDartType(DartType type) {
+    // No need to recurse into dart types, we only care about naming the
+    // constants themselves.
+  }
 }
 
 class Disambiguator<T, U> {
@@ -671,7 +699,7 @@
     if (name?.name == '') {
       writeWord(emptyNameString);
     } else {
-      writeWord(name?.name ?? '<anon>'); // TODO: write library name
+      writeWord(name?.name ?? '<anonymous>'); // TODO: write library name
     }
   }
 
@@ -1163,10 +1191,25 @@
       writeIndentation();
       writeModifier(descriptor.isExternal, 'external');
       writeModifier(descriptor.isStatic, 'static');
-      if (descriptor.member.asMember is Procedure) {
-        writeWord(procedureKindToString(descriptor.kind));
-      } else {
-        writeWord('field');
+      switch (descriptor.kind) {
+        case ExtensionMemberKind.Method:
+          writeWord('method');
+          break;
+        case ExtensionMemberKind.Getter:
+          writeWord('get');
+          break;
+        case ExtensionMemberKind.Setter:
+          writeWord('set');
+          break;
+        case ExtensionMemberKind.Operator:
+          writeWord('operator');
+          break;
+        case ExtensionMemberKind.Field:
+          writeWord('field');
+          break;
+        case ExtensionMemberKind.TearOff:
+          writeWord('tearoff');
+          break;
       }
       writeName(descriptor.name);
       writeSpaced('=');
@@ -1394,6 +1437,10 @@
     writeSymbol('}');
   }
 
+  visitFileUriExpression(FileUriExpression node) {
+    writeExpression(node.expression);
+  }
+
   visitIsExpression(IsExpression node) {
     writeExpression(node.operand, Precedence.BITWISE_OR);
     writeSpaced('is');
@@ -1999,19 +2046,39 @@
     endLine(': ${node.runtimeType}');
   }
 
-  writeNullability(Nullability nullability) {
+  void writeNullability(Nullability nullability, {bool inComment = false}) {
     switch (nullability) {
       case Nullability.legacy:
         writeSymbol('*');
-        state = WORD; // Disallow a word immediately after the '*'.
+        if (!inComment) {
+          state = WORD; // Disallow a word immediately after the '*'.
+        }
         break;
       case Nullability.nullable:
-        writeSymbol('?'); // Disallow a word immediately after the '?'.
+        writeSymbol('?');
+        if (!inComment) {
+          state = WORD; // Disallow a word immediately after the '?'.
+        }
         break;
       case Nullability.neither:
-      case Nullability.nonNullable:
-        // Do nothing.
+        writeSymbol('%');
+        if (!inComment) {
+          state = WORD; // Disallow a word immediately after the '%'.
+        }
         break;
+      case Nullability.nonNullable:
+        if (inComment) {
+          writeSymbol("!");
+        }
+        break;
+    }
+  }
+
+  void writeDartTypeNullability(DartType type, {bool inComment = false}) {
+    if (type is InvalidType) {
+      writeNullability(Nullability.neither);
+    } else {
+      writeNullability(type.nullability, inComment: inComment);
     }
   }
 
@@ -2052,12 +2119,18 @@
 
   visitTypeParameterType(TypeParameterType node) {
     writeTypeParameterReference(node.parameter);
-    writeNullability(node.nullability);
+    writeNullability(node.declaredNullability);
     if (node.promotedBound != null) {
-      writeSpace();
-      writeWord('extends');
-      writeSpace();
+      writeSpaced('&');
       writeType(node.promotedBound);
+
+      writeWord("/* '");
+      writeNullability(node.declaredNullability, inComment: true);
+      writeWord("' & '");
+      writeDartTypeNullability(node.promotedBound, inComment: true);
+      writeWord("' = '");
+      writeNullability(node.nullability, inComment: true);
+      writeWord("' */");
     }
   }
 
@@ -2130,14 +2203,20 @@
     writeConstantReference(node);
     writeSpaced('=');
     writeClassReferenceFromReference(node.classReference);
-    if (!node.classNode.typeParameters.isEmpty) {
+    if (!node.typeArguments.isEmpty) {
       writeSymbol('<');
       writeList(node.typeArguments, writeType);
       writeSymbol('>');
     }
+
     writeSymbol(' {');
-    writeList(node.fieldValues.entries, (entry) {
-      writeWord('${entry.key.asField.name.name}');
+    writeList(node.fieldValues.entries,
+        (core.MapEntry<Reference, Constant> entry) {
+      if (entry.key.node != null) {
+        writeWord('${entry.key.asField.name.name}');
+      } else {
+        writeWord('${entry.key.canonicalName.name}');
+      }
       writeSymbol(':');
       writeConstantReference(entry.value);
     });
@@ -2299,10 +2378,3 @@
   }
   throw 'illegal ProcedureKind: $kind';
 }
-
-class ExpressionPrinter {
-  final Printer writeer;
-  final int minimumPrecedence;
-
-  ExpressionPrinter(this.writeer, this.minimumPrecedence);
-}
diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart
index b29e0e0..18e2cd5 100644
--- a/pkg/kernel/lib/text/text_serialization_verifier.dart
+++ b/pkg/kernel/lib/text/text_serialization_verifier.dart
@@ -396,6 +396,12 @@
   }
 
   @override
+  void visitFileUriExpression(FileUriExpression node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitSymbolConstant(SymbolConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
diff --git a/pkg/kernel/lib/transformations/argument_extraction.dart b/pkg/kernel/lib/transformations/argument_extraction.dart
deleted file mode 100644
index 98af6a5..0000000
--- a/pkg/kernel/lib/transformations/argument_extraction.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library kernel.transformations.argument_extraction;
-
-import '../ast.dart'
-    show
-        Constructor,
-        FieldInitializer,
-        Initializer,
-        Library,
-        LocalInitializer,
-        Component,
-        VariableDeclaration,
-        VariableGet;
-import '../core_types.dart' show CoreTypes;
-import '../visitor.dart' show Transformer;
-
-Component transformComponent(CoreTypes coreTypes, Component component) {
-  new ArgumentExtractionForTesting().visitComponent(component);
-  return component;
-}
-
-void transformLibraries(CoreTypes coreTypes, List<Library> libraries) {
-  var transformer = new ArgumentExtractionForTesting();
-  for (var library in libraries) {
-    transformer.visitLibrary(library);
-  }
-}
-
-class ArgumentExtractionForTesting extends Transformer {
-  visitConstructor(Constructor node) {
-    var newInits = <Initializer>[];
-
-    int nameCounter = 0;
-    for (var fieldInit in node.initializers) {
-      if (fieldInit is FieldInitializer &&
-          !fieldInit.field.name.name.endsWith("_li")) {
-        // Move the body of the initializer to a new local initializer, and
-        // eta-expand the reference to the local initializer in the body of the
-        // field initializer.
-        var value = fieldInit.value;
-
-        var decl = new VariableDeclaration('#li_$nameCounter');
-        decl.initializer = value;
-        var localInit = new LocalInitializer(decl);
-        localInit.parent = node;
-        newInits.add(localInit);
-
-        fieldInit.value = new VariableGet(decl);
-        fieldInit.value.parent = fieldInit;
-
-        ++nameCounter;
-        newInits.add(fieldInit);
-      } else {
-        newInits.add(fieldInit);
-      }
-    }
-
-    node.initializers = newInits;
-    return super.visitConstructor(node);
-  }
-}
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index 3ea9fe2..caa4ffd 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -80,7 +80,9 @@
 
   ExpressionLifter(this.continuationRewriter);
 
-  Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList());
+  Block blockOf(List<Statement> statements) {
+    return new Block(statements.reversed.toList());
+  }
 
   /// Rewrite a toplevel expression (toplevel wrt. a statement).
   ///
@@ -92,7 +94,7 @@
     assert(statements.isEmpty);
     var saved = seenAwait;
     seenAwait = false;
-    Expression result = expression.accept(this);
+    Expression result = expression.accept<TreeNode>(this);
     outer.addAll(statements.reversed);
     statements.clear();
     seenAwait = seenAwait || saved;
@@ -211,25 +213,25 @@
 
   TreeNode visitPropertySet(PropertySet expr) {
     return transform(expr, () {
-      expr.value = expr.value.accept(this)..parent = expr;
-      expr.receiver = expr.receiver.accept(this)..parent = expr;
+      expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
+      expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
   }
 
   TreeNode visitDirectPropertySet(DirectPropertySet expr) {
     return transform(expr, () {
-      expr.value = expr.value.accept(this)..parent = expr;
-      expr.receiver = expr.receiver.accept(this)..parent = expr;
+      expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
+      expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
   }
 
   TreeNode visitArguments(Arguments args) {
     for (var named in args.named.reversed) {
-      named.value = named.value.accept(this)..parent = named;
+      named.value = named.value.accept<TreeNode>(this)..parent = named;
     }
     var positional = args.positional;
     for (var i = positional.length - 1; i >= 0; --i) {
-      positional[i] = positional[i].accept(this)..parent = args;
+      positional[i] = positional[i].accept<TreeNode>(this)..parent = args;
     }
     // Returns the arguments, which is assumed at the call sites because they do
     // not replace the arguments or set parent pointers.
@@ -239,14 +241,14 @@
   TreeNode visitMethodInvocation(MethodInvocation expr) {
     return transform(expr, () {
       visitArguments(expr.arguments);
-      expr.receiver = expr.receiver.accept(this)..parent = expr;
+      expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
   }
 
   TreeNode visitDirectMethodInvocation(DirectMethodInvocation expr) {
     return transform(expr, () {
       visitArguments(expr.arguments);
-      expr.receiver = expr.receiver.accept(this)..parent = expr;
+      expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
     });
   }
 
@@ -272,7 +274,7 @@
     return transform(expr, () {
       var expressions = expr.expressions;
       for (var i = expressions.length - 1; i >= 0; --i) {
-        expressions[i] = expressions[i].accept(this)..parent = expr;
+        expressions[i] = expressions[i].accept<TreeNode>(this)..parent = expr;
       }
     });
   }
@@ -281,7 +283,8 @@
     return transform(expr, () {
       var expressions = expr.expressions;
       for (var i = expressions.length - 1; i >= 0; --i) {
-        expressions[i] = expr.expressions[i].accept(this)..parent = expr;
+        expressions[i] = expr.expressions[i].accept<TreeNode>(this)
+          ..parent = expr;
       }
     });
   }
@@ -289,8 +292,8 @@
   TreeNode visitMapLiteral(MapLiteral expr) {
     return transform(expr, () {
       for (var entry in expr.entries.reversed) {
-        entry.value = entry.value.accept(this)..parent = entry;
-        entry.key = entry.key.accept(this)..parent = entry;
+        entry.value = entry.value.accept<TreeNode>(this)..parent = entry;
+        entry.key = entry.key.accept<TreeNode>(this)..parent = entry;
       }
     });
   }
@@ -302,15 +305,16 @@
     // Right is delimited because it is conditionally evaluated.
     var rightStatements = <Statement>[];
     seenAwait = false;
-    expr.right = delimit(() => expr.right.accept(this), rightStatements)
-      ..parent = expr;
+    expr.right =
+        delimit(() => expr.right.accept<TreeNode>(this), rightStatements)
+          ..parent = expr;
     var rightAwait = seenAwait;
 
     if (rightStatements.isEmpty) {
       // Easy case: right did not emit any statements.
       seenAwait = shouldName;
       return transform(expr, () {
-        expr.left = expr.left.accept(this)..parent = expr;
+        expr.left = expr.left.accept<TreeNode>(this)..parent = expr;
         seenAwait = seenAwait || rightAwait;
       });
     }
@@ -348,7 +352,7 @@
     statements.add(new ExpressionStatement(new VariableSet(result, test)));
 
     seenAwait = false;
-    test.receiver = test.receiver.accept(this)..parent = test;
+    test.receiver = test.receiver.accept<TreeNode>(this)..parent = test;
 
     ++nameIndex;
     seenAwait = seenAwait || rightAwait;
@@ -362,22 +366,22 @@
 
     var thenStatements = <Statement>[];
     seenAwait = false;
-    expr.then = delimit(() => expr.then.accept(this), thenStatements)
+    expr.then = delimit(() => expr.then.accept<TreeNode>(this), thenStatements)
       ..parent = expr;
     var thenAwait = seenAwait;
 
     var otherwiseStatements = <Statement>[];
     seenAwait = false;
-    expr.otherwise =
-        delimit(() => expr.otherwise.accept(this), otherwiseStatements)
-          ..parent = expr;
+    expr.otherwise = delimit(
+        () => expr.otherwise.accept<TreeNode>(this), otherwiseStatements)
+      ..parent = expr;
     var otherwiseAwait = seenAwait;
 
     if (thenStatements.isEmpty && otherwiseStatements.isEmpty) {
       // Easy case: neither then nor otherwise emitted any statements.
       seenAwait = shouldName;
       return transform(expr, () {
-        expr.condition = expr.condition.accept(this)..parent = expr;
+        expr.condition = expr.condition.accept<TreeNode>(this)..parent = expr;
         seenAwait = seenAwait || thenAwait || otherwiseAwait;
       });
     }
@@ -401,7 +405,7 @@
     statements.add(branch);
 
     seenAwait = false;
-    branch.condition = branch.condition.accept(this)..parent = branch;
+    branch.condition = branch.condition.accept<TreeNode>(this)..parent = branch;
 
     ++nameIndex;
     seenAwait = seenAwait || thenAwait || otherwiseAwait;
@@ -445,7 +449,8 @@
 
     seenAwait = false;
     var index = nameIndex;
-    arguments.positional[0] = expr.operand.accept(this)..parent = arguments;
+    arguments.positional[0] = expr.operand.accept<TreeNode>(this)
+      ..parent = arguments;
 
     if (shouldName && index + 1 > nameIndex) nameIndex = index + 1;
     seenAwait = true;
@@ -458,7 +463,7 @@
   }
 
   TreeNode visitLet(Let expr) {
-    var body = expr.body.accept(this);
+    var body = expr.body.accept<TreeNode>(this);
 
     VariableDeclaration variable = expr.variable;
     if (seenAwait) {
@@ -479,7 +484,7 @@
       statements.add(variable);
       var index = nameIndex;
       seenAwait = false;
-      variable.initializer = variable.initializer.accept(this)
+      variable.initializer = variable.initializer.accept<TreeNode>(this)
         ..parent = variable;
       // Temporaries used in the initializer or the body are not live but the
       // temporary used for the body is.
@@ -492,7 +497,7 @@
       return transform(expr, () {
         // The body has already been translated.
         expr.body = body..parent = expr;
-        variable.initializer = variable.initializer.accept(this)
+        variable.initializer = variable.initializer.accept<TreeNode>(this)
           ..parent = variable;
       });
     }
@@ -506,10 +511,10 @@
 
   TreeNode visitBlockExpression(BlockExpression expr) {
     return transform(expr, () {
-      expr.value = expr.value.accept(this)..parent = expr;
+      expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
       List<Statement> body = <Statement>[];
       for (Statement stmt in expr.body.statements.reversed) {
-        Statement translation = stmt.accept(this);
+        Statement translation = stmt.accept<TreeNode>(this);
         if (translation != null) body.add(translation);
       }
       expr.body = new Block(body.reversed.toList())..parent = expr;
diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart
index a45f713..3e87ef2 100644
--- a/pkg/kernel/lib/transformations/continuation.dart
+++ b/pkg/kernel/lib/transformations/continuation.dart
@@ -16,6 +16,7 @@
   static const awaitJumpVar = ':await_jump_var';
   static const awaitContextVar = ':await_ctx_var';
   static const asyncStackTraceVar = ':async_stack_trace';
+  static const controllerStreamVar = ':controller_stream';
   static const exceptionParam = ':exception';
   static const stackTraceParam = ':stack_trace';
 
@@ -59,11 +60,11 @@
   RecursiveContinuationRewriter(this.helper);
 
   Component rewriteComponent(Component node) {
-    return node.accept(this);
+    return node.accept<TreeNode>(this);
   }
 
   Library rewriteLibrary(Library node) {
-    return node.accept(this);
+    return node.accept<TreeNode>(this);
   }
 
   visitProcedure(Procedure node) {
@@ -135,7 +136,7 @@
   TreeNode visitTryCatch(TryCatch node) {
     if (node.body != null) {
       ++currentTryDepth;
-      node.body = node.body.accept(this);
+      node.body = node.body.accept<TreeNode>(this);
       node.body?.parent = node;
       --currentTryDepth;
     }
@@ -149,13 +150,13 @@
   TreeNode visitTryFinally(TryFinally node) {
     if (node.body != null) {
       ++currentTryDepth;
-      node.body = node.body.accept(this);
+      node.body = node.body.accept<TreeNode>(this);
       node.body?.parent = node;
       --currentTryDepth;
     }
     if (node.finalizer != null) {
       ++currentCatchDepth;
-      node.finalizer = node.finalizer.accept(this);
+      node.finalizer = node.finalizer.accept<TreeNode>(this);
       node.finalizer?.parent = node;
       --currentCatchDepth;
     }
@@ -233,14 +234,14 @@
     //    :iterator.isYieldEach=
     // and return `true` as long as it did something and `false` when it's done.
     return new Block(<Statement>[
-      enclosingFunction.body.accept(this),
+      enclosingFunction.body.accept<TreeNode>(this),
       new ReturnStatement(new BoolLiteral(false))
         ..fileOffset = enclosingFunction.fileEndOffset
     ]);
   }
 
   visitYieldStatement(YieldStatement node) {
-    Expression transformedExpression = node.expression.accept(this);
+    Expression transformedExpression = node.expression.accept<TreeNode>(this);
 
     var statements = <Statement>[];
     if (node.isYieldStar) {
@@ -398,7 +399,7 @@
     var saved = statements;
     statements = <Statement>[];
     for (var statement in stmt.statements) {
-      statement.accept(this);
+      statement.accept<TreeNode>(this);
     }
     saved.add(new Block(statements));
     statements = saved;
@@ -414,7 +415,7 @@
     var saved = statements;
     statements = <Statement>[];
     for (var statement in stmt.statements) {
-      statement.accept(this);
+      statement.accept<TreeNode>(this);
     }
     saved.add(new Block(statements));
     statements = saved;
@@ -483,7 +484,7 @@
   Statement visitDelimited(Statement stmt) {
     var saved = statements;
     statements = <Statement>[];
-    stmt.accept(this);
+    stmt.accept<TreeNode>(this);
     Statement result =
         statements.length == 1 ? statements.first : new Block(statements);
     statements = saved;
@@ -635,7 +636,7 @@
 
     // Place the loop variable declarations at the beginning of the body
     // statements and move their initializers to a guarded list of statements.
-    // Add assignments to the loop variables from the previous iteration's temp
+    // Add assignments to the loop variables from the previous iterations temp
     // variables before the updates.
     //
     // temps.first is the flag 'first'.
@@ -811,7 +812,7 @@
         iteratorVariable,
         tryFinally
       ]);
-      block.accept(this);
+      block.accept<TreeNode>(this);
     } else {
       stmt.iterable = expressionRewriter.rewrite(stmt.iterable, statements)
         ..parent = stmt;
@@ -892,7 +893,7 @@
   }
 
   TreeNode visitFunctionDeclaration(FunctionDeclaration stmt) {
-    stmt.function = stmt.function.accept(this)..parent = stmt;
+    stmt.function = stmt.function.accept<TreeNode>(this)..parent = stmt;
     statements.add(stmt);
     return null;
   }
@@ -919,7 +920,7 @@
 
     // dynamic :controller_stream;
     VariableDeclaration controllerStreamVariable =
-        new VariableDeclaration(":controller_stream");
+        new VariableDeclaration(ContinuationVariables.controllerStreamVar);
     statements.add(controllerStreamVariable);
 
     setupAsyncContinuations(statements);
diff --git a/pkg/kernel/lib/transformations/coq.dart b/pkg/kernel/lib/transformations/coq.dart
deleted file mode 100644
index f668737..0000000
--- a/pkg/kernel/lib/transformations/coq.dart
+++ /dev/null
@@ -1,528 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// This transformations outputs a Coq definitions to resemble the Dart syntax
-// tree.
-//
-// Classes that are supposed to be converted are marked with the `@coq`
-// annotation. Some fields within these classes will be converted according to
-// the following rules:
-//
-// 1. A field labeled `@nocoq` will not be converted.
-//
-// 2. A field labeled `@coq` or `@coqopt` will be converted unless it's type is
-// unuspported, in which case an exception will be raised.
-//
-// 3. An unannotated field will be converted if it has type `T` or `List<T>`,
-// where `T` is a class marked for conversion.
-//
-// Classes marked `@coqref` are referenced by natural numbered IDs wherever
-// fields of their type appear, and we have a finite map resolving these IDs.
-// This breaks cycles in the AST graph and provides a way to identify nodes for
-// substitution.
-//
-// All classes with data members are given an induction type definition with a
-// single constructor, holding the data members of that class. Classes with
-// subclasses are also given an inductive definition enumerating all (converted)
-// subclasses. Their data-member type definition will appear inline in the data
-// member definitions for their leaf subclasses. Due to this representation,
-// converted classes with subclasses must be abstract.
-//
-// Since the whole syntax tree is mutually recursive, all the types are dumped
-// into one big "Inductive ... with ... with ... " definition.
-
-library kernel.transformations.coq;
-
-import 'dart:io';
-import '../ast.dart';
-import '../coq_annot.dart' as coq_annot;
-import '../core_types.dart' show CoreTypes;
-
-enum RefStyle { direct, identified }
-
-enum FieldStyle { list, optional, normal }
-
-class CoqFieldInfo {
-  // Only one of these two may be non-null.
-  final CoqClassInfo type;
-  final String primitiveCoqType;
-
-  final String dartName;
-  final FieldStyle style;
-  bool definitional = false;
-
-  String get innerRefType => type == null ? primitiveCoqType : type.refType;
-
-  String get refType {
-    if (type != null) {
-      var rt = definitional ? type.coqType : type.refType;
-      if (style == FieldStyle.list) {
-        return "list $rt";
-      } else if (style == FieldStyle.optional) {
-        return "option $rt";
-      } else {
-        return rt;
-      }
-    } else {
-      if (style == FieldStyle.list) {
-        return "list " + primitiveCoqType;
-      } else if (style == FieldStyle.optional) {
-        return "option " + primitiveCoqType;
-      } else {
-        return primitiveCoqType;
-      }
-    }
-  }
-
-  CoqFieldInfo(this.dartName, this.type, this.primitiveCoqType, this.style);
-}
-
-class CoqClassInfo {
-  final Class cls;
-  final RefStyle refStyle;
-
-  List<CoqClassInfo> subs = <CoqClassInfo>[];
-  List<CoqFieldInfo> fields = <CoqFieldInfo>[];
-
-  bool needsOption = false;
-  bool needsList = false;
-
-  String get coqType => coqifyName(cls.name);
-  String get coqTypeCaps => coqifyName(cls.name, capitalize: true);
-  String get abbrevName => abbrev(cls.name);
-  String get abbrevNameCaps => abbrev(cls.name, capitalize: true);
-  String get refType => refStyle == RefStyle.direct ? coqType : "nat";
-
-  CoqClassInfo(this.cls, this.refStyle);
-
-  Iterable<CoqClassInfo> supersWithData(CoqLibInfo info) sync* {
-    for (Supertype st = cls.supertype;
-        st != null;
-        st = st.classNode.supertype) {
-      Class spr = st.classNode;
-      var sprInfo = info.classes[spr];
-      if (sprInfo == null) break;
-      if (sprInfo.fields.length == 0) continue;
-      yield sprInfo;
-    }
-  }
-}
-
-class CoqLibInfo {
-  final Map<Class, CoqClassInfo> classes = <Class, CoqClassInfo>{};
-  CoqLibInfo();
-}
-
-// Get the number associated with the annotation from `coq_annot.dart` on a
-// [Field] or [Class] if one exists, and 0 otherwise. Throws an exception if
-// invalid or multiple annotations are discoverted.
-int getCoqAnnot(NamedNode N, List<Expression> annotations) {
-  if (coq_annot.coqEnums.contains("$N")) {
-    return coq_annot.coq;
-  }
-
-  int annot = 0;
-  for (var A in annotations) {
-    if (A is StaticGet) {
-      var target = A.targetReference.node;
-      var parent = target.parent;
-      if (parent is Library) {
-        if (parent is NamedNode && parent.name == "kernel.coq_annot") {
-          if (target is Field) {
-            if (annot != 0) {
-              throw new Exception("ERROR: Multiple Coq annotations on ${N}!");
-            }
-            switch ("${target.name}") {
-              case "coq":
-                annot = coq_annot.coq;
-                break;
-              case "coqref":
-                annot = coq_annot.coqref;
-                break;
-              case "nocoq":
-                annot = coq_annot.nocoq;
-                break;
-              case "coqopt":
-                annot = coq_annot.coqopt;
-                break;
-              case "coqsingle":
-                annot = coq_annot.coqsingle;
-                break;
-              case "coqdef":
-                annot = coq_annot.coqdef;
-                break;
-              case "coqsingledef":
-                annot = coq_annot.coqsingledef;
-                break;
-              default:
-                throw new Exception("ERROR: Invalid Coq annotation on ${N}!");
-            }
-          } else {
-            throw new Exception("ERROR: Invalid Coq annotation on ${N}!");
-          }
-        }
-      }
-    }
-  }
-  return annot;
-}
-
-// Determine which classes we're going to convert.
-class CoqPass1 extends RecursiveVisitor {
-  CoqLibInfo info;
-  CoqPass1(this.info);
-
-  visitClass(Class C) {
-    int annot = getCoqAnnot(C, C.annotations);
-    if (annot == 0) return;
-
-    if (annot != coq_annot.coq && annot != coq_annot.coqref) {
-      throw new Exception("ERROR: Invalid Coq annotation on ${C.name}!");
-    }
-
-    info.classes[C] = new CoqClassInfo(
-        C, annot == coq_annot.coq ? RefStyle.direct : RefStyle.identified);
-  }
-}
-
-// Determine which fields we're going to convert and which classes have
-// converted subclasses.
-class CoqPass2 extends RecursiveVisitor {
-  CoqLibInfo info;
-  CoreTypes coreTypes;
-  CoqPass2(this.info, this.coreTypes);
-
-  CoqClassInfo currentClass = null;
-
-  String getCoqPrimitiveType(Class cls) {
-    if (cls == coreTypes.stringClass) {
-      return "string";
-    } else if (cls == coreTypes.boolClass) {
-      return "bool";
-    } else if (cls == coreTypes.intClass) {
-      return "nat";
-    } else {
-      return null;
-    }
-  }
-
-  visitClass(Class C) {
-    var classInfo = info.classes[C];
-    if (classInfo == null) return;
-
-    if (C.supertype != null) {
-      Class spr = C.supertype.classNode;
-      var sprInfo = info.classes[spr];
-      if (sprInfo != null) {
-        sprInfo.subs.add(classInfo);
-      }
-    }
-
-    currentClass = classInfo;
-    C.visitChildren(this);
-    currentClass = null;
-  }
-
-  visitField(Field F) {
-    if (currentClass == null) return;
-
-    int annot = getCoqAnnot(F, F.annotations);
-    if (annot == coq_annot.nocoq) return;
-
-    var type = F.type;
-    if (type is! InterfaceType) return;
-
-    var interfaceType = type as InterfaceType;
-
-    var cls = null;
-    bool isList = false;
-
-    if (interfaceType.classNode == coreTypes.listClass) {
-      isList = annot != coq_annot.coqsingle && annot != coq_annot.coqsingledef;
-      if (interfaceType.typeArguments.length != 1) return;
-      var elemType = interfaceType.typeArguments[0];
-      if (elemType is InterfaceType) {
-        cls = elemType.classNode;
-      } else if (annot == coq_annot.coqopt) {
-        throw new Exception("ERROR: Field $F may not be optional.");
-      }
-    } else {
-      cls = interfaceType.classNode;
-    }
-
-    FieldStyle style = isList
-        ? FieldStyle.list
-        : (annot == coq_annot.coqopt ? FieldStyle.optional : FieldStyle.normal);
-
-    CoqFieldInfo fieldInfo = null;
-    var primitive = getCoqPrimitiveType(cls);
-    var fieldName = F.name.name;
-
-    if (primitive != null) {
-      if (annot == 0) return;
-      fieldInfo = new CoqFieldInfo(fieldName, null, primitive, style);
-    } else {
-      var fieldClassInfo = info.classes[cls];
-      if (fieldClassInfo == null) {
-        return;
-      }
-      fieldInfo = new CoqFieldInfo(fieldName, fieldClassInfo, null, style);
-
-      if (style == FieldStyle.optional) {
-        fieldClassInfo.needsOption = true;
-      } else if (style == FieldStyle.list) {
-        fieldClassInfo.needsList = true;
-      }
-
-      if (annot == coq_annot.coqdef || annot == coq_annot.coqsingledef) {
-        fieldInfo.definitional = true;
-      }
-    }
-
-    currentClass.fields.add(fieldInfo);
-  }
-}
-
-// Conventional Coq code uses underscores instead of camelCase as Dart code
-// does. This function converts the Dart convention to the Coq convention.
-final coqReserved = <String>["let"];
-String coqifyName(String S, {bool capitalize: false}) {
-  List<int> codes = <int>[];
-  bool skipUnderscore = false;
-  for (int i = 0; i < S.length; ++i) {
-    var c = S.codeUnitAt(i);
-    if (c >= "A".codeUnits[0] && c <= "Z".codeUnits[0]) {
-      if (i > 0 && !skipUnderscore) {
-        codes.add("_".codeUnitAt(0));
-      }
-      if (!capitalize) c += ("a".codeUnits[0] - "A".codeUnits[0]);
-      codes.add(c);
-    } else {
-      codes.add(c);
-    }
-    skipUnderscore = c == "_".codeUnits[0];
-  }
-  var name = new String.fromCharCodes(codes);
-  if (coqReserved.contains(name)) {
-    name = "dart_" + name;
-  }
-  return name;
-}
-
-// Give an abbreviation of a identifying by combining the capital letters of the
-// identifier. For example, "ProcedureKind" becomes "pk" or "PK".
-String abbrev(String S, {bool capitalize: false}) {
-  List<int> codes = <int>[];
-  for (var c in S.codeUnits)
-    if (c >= 65 && c <= 90) codes.add(capitalize ? c : c + 32);
-  return new String.fromCharCodes(codes);
-}
-
-void outputCoqImports() {
-  print("""
-Require Import Common.
-""");
-}
-
-void outputCoqSyntax(CoqLibInfo info) {
-  int defN = 0;
-  defkw() => defN++ > 0 ? "with" : "Inductive";
-  for (var classInfo in info.classes.values) {
-    bool isAbstract = classInfo.subs.length > 0;
-
-    Class cls = classInfo.cls;
-    var coqName = classInfo.coqType;
-
-    if (classInfo.cls.isEnum) {
-      var enums = [];
-      for (var fld in classInfo.fields) {
-        if (fld.dartName == "values") continue;
-        enums.add(coqifyName(fld.dartName, capitalize: true));
-      }
-      print("${defkw()} $coqName : Set := ${enums.join(" | ")}\n");
-      continue;
-    }
-
-    if (!isAbstract || classInfo.fields.length > 0) {
-      var suffix = isAbstract ? "_data" : "";
-      var dataTypeName = coqName + suffix;
-      var dataCtorName = coqifyName(cls.name, capitalize: true);
-
-      print("${defkw()} ${dataTypeName} : Set :=");
-      print("  | ${dataCtorName} : ");
-
-      // Insert fields for superclasses.
-      int arw = 0;
-      arrow() => arw++ == 0 ? "" : "-> ";
-
-      if (classInfo.refStyle == RefStyle.identified) {
-        print("      ${arrow()}nat");
-      }
-
-      for (var sprInfo in classInfo.supersWithData(info)) {
-        print("      ${arrow()}${sprInfo.coqType}_data");
-      }
-
-      for (CoqFieldInfo fld in classInfo.fields) {
-        print("      ${arrow()}${fld.refType} (* ${fld.dartName} *)");
-      }
-
-      print("      ${arrow()}$dataTypeName\n");
-    }
-
-    if (classInfo.subs.length > 0) {
-      print("${defkw()} $coqName : Set :=");
-
-      var abbrevName = abbrev(cls.name, capitalize: true);
-      for (var sub in classInfo.subs) {
-        var subTypeName = coqifyName(sub.cls.name);
-        var ctorName = coqifyName(sub.cls.name, capitalize: true);
-        print("  | ${abbrevName}_${ctorName} : ${subTypeName} -> $coqName");
-      }
-
-      print("\n");
-    }
-  }
-  print(".\n");
-}
-
-void outputCoqStore(info) {
-  print("Record ast_store : Type := Ast_Store {");
-  for (var classInfo in info.classes.values) {
-    if (classInfo.refStyle != RefStyle.identified) continue;
-    print("  ${classInfo.abbrevName}_refs : NatMap.t ${classInfo.coqType};");
-  }
-  print("}.\n");
-}
-
-void outputCoqSyntaxValidity(CoqLibInfo info) {
-  int defN = 0;
-  defkw() => defN++ > 0 ? "with" : "Fixpoint";
-
-  validityPredicate(CoqClassInfo CI) {
-    if (CI.refStyle == RefStyle.identified) {
-      var mapName = "${CI.abbrevName}_refs";
-      return (X) => "NatMap.In $X ($mapName ast)";
-    } else {
-      return (X) => "${CI.coqType}_validity ast $X";
-    }
-  }
-
-  for (var CI in info.classes.values) {
-    stdout.write(
-        "${defkw()} ${CI.coqType}_validity (ast : ast_store) (T : ${CI.coqType}) {struct T} : Prop :=");
-    if (CI.cls.isEnum) {
-      stdout.write(" True\n");
-      continue;
-    } else {
-      stdout.write("\n");
-    }
-
-    print("  match T with");
-    for (var sub in CI.subs) {
-      print(
-          "    | ${CI.abbrevNameCaps}_${sub.coqTypeCaps} ST => ${sub.coqType}_validity ast ST");
-    }
-
-    if (CI.subs.length > 0) {
-      print("end");
-      if (CI.fields.length == 0) continue;
-      print(
-          "${defkw()} ${CI.coqType}_data_validity (ast : ast_store) (T : ${CI.coqType}_data) {struct T}: Prop :=");
-      print("  match T with");
-    }
-
-    int i = 0;
-    var fieldNames = [];
-    var validityClauses = [];
-
-    for (var SI in CI.supersWithData(info)) {
-      var f = "f${i++}";
-      fieldNames.add(f);
-      validityClauses.add("${SI.coqType}_data_validity ast $f");
-    }
-
-    for (var fld in CI.fields) {
-      if (fld.type == null) {
-        fieldNames.add("_");
-        continue;
-      }
-
-      var f = "f${i++}";
-      fieldNames.add(f);
-
-      var pred;
-      if (fld.style == FieldStyle.normal) {
-        pred = validityPredicate(fld.type)(f);
-      } else if (fld.style == FieldStyle.list) {
-        pred = "${fld.type.coqType}_list_validity ast $f";
-      } else if (fld.style == FieldStyle.optional) {
-        pred = "${fld.type.coqType}_option_validity ast $f";
-      }
-
-      validityClauses.add(pred);
-    }
-
-    var clause = "True";
-    if (validityClauses.length > 0) {
-      clause = validityClauses.join(" /\\\n        ");
-    }
-
-    print(
-        "    | ${CI.coqTypeCaps} ${fieldNames.join(" ")} =>\n        $clause");
-    print("  end");
-  }
-
-  for (var CI in info.classes.values) {
-    var pred = validityPredicate(CI)("X");
-    if (CI.needsList) {
-      var def = """
-with ${CI.coqType}_list_validity (ast : ast_store) (L : ${CI.coqType}_list) {struct L} : Prop :=
-  match L with
-    | ${CI.coqType}_nil => True
-    | ${CI.coqType}_cons X XS => $pred /\\ ${CI.coqType}_list_validity ast XS
-  end""";
-      print(def);
-    }
-    if (CI.needsOption) {
-      var def = """
-with ${CI.coqType}_option_validity (ast : ast_store) (O : ${CI.coqType}_option) {struct O} : Prop :=
-  match O with
-    | ${CI.coqType}_none => True
-    | ${CI.coqType}_some X => $pred
-  end""";
-      print(def);
-    }
-  }
-
-  print(".\n");
-}
-
-void outputCoqStoreValidity(CoqLibInfo info) {
-  var clauses = [];
-  for (var CI in info.classes.values) {
-    if (CI.refStyle != RefStyle.identified) continue;
-    var mapName = "${CI.abbrevName}_refs";
-    clauses.add(
-        "  forall (n : nat), forall (X : ${CI.coqType}), NatMap.MapsTo n X ($mapName ast) -> ${CI.coqType}_validity ast X");
-  }
-  var clause = clauses.join(" /\\\n");
-  print(
-      "Definition ast_store_validity (ast : ast_store) : Prop := \n$clause\n.");
-}
-
-Component transformComponent(CoreTypes coreTypes, Component component) {
-  for (Library lib in component.libraries) {
-    // TODO(30610): Ideally we'd output to the file in the coq annotation on the
-    // library name, but currently fasta throws away annotations on libraries.
-    // Instead, we just special case "kernel.ast" and output to stdout.
-    if ("$lib" != "kernel.ast") continue;
-    var info = new CoqLibInfo();
-    (new CoqPass1(info)).visitLibrary(lib);
-    (new CoqPass2(info, coreTypes)).visitLibrary(lib);
-    outputCoqImports();
-    outputCoqSyntax(info);
-  }
-  return component;
-}
diff --git a/pkg/kernel/lib/transformations/mixin_full_resolution.dart b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
index 4a401fa..5081b9e 100644
--- a/pkg/kernel/lib/transformations/mixin_full_resolution.dart
+++ b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
@@ -181,7 +181,7 @@
           if (src.positionalParameters.length !=
                   dst.positionalParameters.length ||
               src.namedParameters.length != dst.namedParameters.length) {
-            // A compile time error has already occured, but don't crash below,
+            // A compile time error has already occurred, but don't crash below,
             // and don't add several procedures with the same name to the class.
             continue outer;
           }
diff --git a/pkg/kernel/lib/transformations/sanitize_for_vm.dart b/pkg/kernel/lib/transformations/sanitize_for_vm.dart
deleted file mode 100644
index afe812d..0000000
--- a/pkg/kernel/lib/transformations/sanitize_for_vm.dart
+++ /dev/null
@@ -1,24 +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.
-library kernel.transformations.fixvm;
-
-import '../ast.dart';
-
-/// Ensures that classes all have either a constructor or a procedure.
-///
-/// VM-specific constraints that don't fit in anywhere else can be put here.
-class SanitizeForVM {
-  void transform(Component component) {
-    for (var library in component.libraries) {
-      for (var class_ in library.classes) {
-        if (class_.constructors.isEmpty && class_.procedures.isEmpty) {
-          class_.addMember(new Constructor(
-              new FunctionNode(new EmptyStatement()),
-              name: new Name(''),
-              isSynthetic: true));
-        }
-      }
-    }
-  }
-}
diff --git a/pkg/kernel/lib/transformations/setup_builtin_library.dart b/pkg/kernel/lib/transformations/setup_builtin_library.dart
deleted file mode 100644
index 07adcb4..0000000
--- a/pkg/kernel/lib/transformations/setup_builtin_library.dart
+++ /dev/null
@@ -1,50 +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.
-
-library kernel.transformations.setup_builtin_library;
-
-import '../ast.dart';
-
-// The DartVM has a special `dart:_builtin` library which exposes a
-// `_getMainClosure()` method.  We need to change this method to return a
-// closure of `main()`.
-Component transformComponent(Component component,
-    {String libraryUri: 'dart:_builtin'}) {
-  Procedure mainMethod = component.mainMethod;
-
-  Library builtinLibrary;
-  for (Library library in component.libraries) {
-    if (library.importUri.toString() == libraryUri) {
-      builtinLibrary = library;
-      break;
-    }
-  }
-
-  if (builtinLibrary == null) {
-    throw new Exception('Could not find "dart:_builtin" library');
-  }
-
-  FunctionNode getMainClosure;
-  for (Procedure procedure in builtinLibrary.procedures) {
-    if (procedure.name.name == '_getMainClosure') {
-      getMainClosure = procedure.function;
-      break;
-    }
-  }
-
-  if (getMainClosure == null) {
-    throw new Exception('Could not find "_getMainClosure" in "$libraryUri"');
-  }
-
-  if (mainMethod != null) {
-    var returnMainStatement = new ReturnStatement(new StaticGet(mainMethod));
-    getMainClosure.body = returnMainStatement;
-    returnMainStatement.parent = getMainClosure;
-  } else {
-    // TODO(ahe): This should throw no such method error.
-    getMainClosure.body = null;
-  }
-
-  return component;
-}
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index d847558..d368c2d 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -241,8 +241,8 @@
   /// [first] if they overlap.
   ///
   /// Neither substitution is applied to the results of the other, so this does
-  /// *not* correspond to a sequence of two subsitutions. For example, combining
-  /// `{T -> List<G>}` with `{G -> String}` does not correspond to
+  /// *not* correspond to a sequence of two substitutions. For example,
+  /// combining `{T -> List<G>}` with `{G -> String}` does not correspond to
   /// `{T -> List<String>}` because the result from substituting `T` is not
   /// searched for occurences of `G`.
   static Substitution combine(Substitution first, Substitution second) {
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 8faae52..6c9af84 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -725,6 +725,11 @@
   }
 
   @override
+  DartType visitFileUriExpression(FileUriExpression node) {
+    return visitExpression(node.expression);
+  }
+
+  @override
   DartType visitStringLiteral(StringLiteral node) {
     return environment.stringType;
   }
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 1bfcb8b..503655e 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -202,6 +202,14 @@
     currentLibrary = null;
   }
 
+  visitExtension(Extension node) {
+    declareTypeParameters(node.typeParameters);
+    final oldParent = enterParent(node);
+    node.visitChildren(this);
+    exitParent(oldParent);
+    undeclareTypeParameters(node.typeParameters);
+  }
+
   void checkTypedef(Typedef node) {
     var state = typedefState[node];
     if (state == TypedefState.Done) return;
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index bdea433..d3dc88e 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -43,6 +43,7 @@
   R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
   R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
   R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
+  R visitFileUriExpression(FileUriExpression node) => defaultExpression(node);
   R visitIsExpression(IsExpression node) => defaultExpression(node);
   R visitAsExpression(AsExpression node) => defaultExpression(node);
   R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@@ -170,6 +171,7 @@
   R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
   R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
   R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
+  R visitFileUriExpression(FileUriExpression node) => defaultExpression(node);
   R visitIsExpression(IsExpression node) => defaultExpression(node);
   R visitAsExpression(AsExpression node) => defaultExpression(node);
   R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@@ -403,7 +405,7 @@
 /// value for each subnode. The visitor caches the computed values ensuring that
 /// each subnode is only visited once.
 class ComputeOnceConstantVisitor<R> implements _ConstantCallback<R> {
-  _ConstantCallbackVisitor _visitor;
+  _ConstantCallbackVisitor<R> _visitor;
   Map<Constant, R> cache = new LinkedHashMap.identity();
 
   ComputeOnceConstantVisitor() {
@@ -685,6 +687,8 @@
       defaultExpression(node, arg);
   R visitInstanceCreation(InstanceCreation node, T arg) =>
       defaultExpression(node, arg);
+  R visitFileUriExpression(FileUriExpression node, T arg) =>
+      defaultExpression(node, arg);
   R visitIsExpression(IsExpression node, T arg) => defaultExpression(node, arg);
   R visitAsExpression(AsExpression node, T arg) => defaultExpression(node, arg);
   R visitSymbolLiteral(SymbolLiteral node, T arg) =>
diff --git a/pkg/kernel/pubspec.yaml b/pkg/kernel/pubspec.yaml
index 2ee72eb..d28cdb0 100644
--- a/pkg/kernel/pubspec.yaml
+++ b/pkg/kernel/pubspec.yaml
@@ -1,7 +1,7 @@
 name: kernel
 # Currently, kernel API is not stable and users should
 # not depend on semver semantics when depending on this package.
-version: 0.3.23
+version: 0.3.24
 author: Dart Team <misc@dartlang.org>
 description: Dart IR (Intermediate Representation)
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/kernel
diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
index affbf9f..7f32330 100644
--- a/pkg/kernel/test/verify_test.dart
+++ b/pkg/kernel/test/verify_test.dart
@@ -99,14 +99,14 @@
   negativeTest(
       'Class type parameter from another class',
       "Type parameter 'test_lib::OtherClass::OtherT' referenced out of scope,"
-      " parent is: 'test_lib::OtherClass'.", (TestHarness test) {
+          " parent is: 'test_lib::OtherClass'.", (TestHarness test) {
     test.addNode(
         TypeLiteral(new TypeParameterType(test.otherClass.typeParameters[0])));
   });
   negativeTest(
       'Class type parameter in static method',
       "Type parameter 'test_lib::TestClass::T' referenced from static context,"
-      " parent is: 'test_lib::TestClass'.", (TestHarness test) {
+          " parent is: 'test_lib::TestClass'.", (TestHarness test) {
     test.addNode(Procedure(
         new Name('bar'),
         ProcedureKind.Method,
@@ -117,7 +117,7 @@
   negativeTest(
       'Class type parameter in static field',
       "Type parameter 'test_lib::TestClass::T' referenced from static context,"
-      " parent is: 'test_lib::TestClass'.", (TestHarness test) {
+          " parent is: 'test_lib::TestClass'.", (TestHarness test) {
     test.addNode(Field(new Name('field'),
         initializer:
             new TypeLiteral(new TypeParameterType(test.classTypeParameter)),
@@ -147,13 +147,13 @@
   negativeTest(
       'Interface type arity too low',
       "Type test_lib::OtherClass* provides 0 type arguments"
-      " but the class declares 1 parameters.", (TestHarness test) {
+          " but the class declares 1 parameters.", (TestHarness test) {
     test.addNode(TypeLiteral(new InterfaceType(test.otherClass, [])));
   });
   negativeTest(
       'Interface type arity too high',
       "Type test_lib::OtherClass<dynamic, dynamic>* provides 2 type arguments"
-      " but the class declares 1 parameters.", (TestHarness test) {
+          " but the class declares 1 parameters.", (TestHarness test) {
     test.addNode(TypeLiteral(new InterfaceType(
         test.otherClass, [new DynamicType(), new DynamicType()])));
   });
@@ -173,7 +173,7 @@
   negativeTest(
       'Missing block parent pointer',
       "Incorrect parent pointer on ReturnStatement:"
-      " expected 'Block', but found: 'Null'.", (TestHarness test) {
+          " expected 'Block', but found: 'Null'.", (TestHarness test) {
     var block = new Block([]);
     block.statements.add(new ReturnStatement());
     test.addNode(block);
@@ -181,7 +181,7 @@
   negativeTest(
       'Missing function parent pointer',
       "Incorrect parent pointer on FunctionNode:"
-      " expected 'Procedure', but found: 'Null'.", (TestHarness test) {
+          " expected 'Procedure', but found: 'Null'.", (TestHarness test) {
     var procedure = new Procedure(new Name('bar'), ProcedureKind.Method, null);
     procedure.function = new FunctionNode(new EmptyStatement());
     test.addNode(procedure);
@@ -212,7 +212,7 @@
   negativeTest(
       'StaticInvocation with too many parameters',
       "StaticInvocation with incompatible arguments for"
-      " 'test_lib::TestClass::bar'.", (TestHarness test) {
+          " 'test_lib::TestClass::bar'.", (TestHarness test) {
     var method = new Procedure(new Name('bar'), ProcedureKind.Method,
         new FunctionNode(new EmptyStatement()),
         isStatic: true);
@@ -222,7 +222,7 @@
   negativeTest(
       'StaticInvocation with too few parameters',
       "StaticInvocation with incompatible arguments for"
-      " 'test_lib::TestClass::bar'.", (TestHarness test) {
+          " 'test_lib::TestClass::bar'.", (TestHarness test) {
     var method = new Procedure(
         new Name('bar'),
         ProcedureKind.Method,
@@ -235,7 +235,7 @@
   negativeTest(
       'StaticInvocation with unmatched named parameter',
       "StaticInvocation with incompatible arguments for"
-      " 'test_lib::TestClass::bar'.", (TestHarness test) {
+          " 'test_lib::TestClass::bar'.", (TestHarness test) {
     var method = new Procedure(new Name('bar'), ProcedureKind.Method,
         new FunctionNode(new EmptyStatement()),
         isStatic: true);
@@ -248,7 +248,7 @@
   negativeTest(
       'StaticInvocation with missing type argument',
       "StaticInvocation with wrong number of type arguments for"
-      " 'test_lib::TestClass::bar'.", (TestHarness test) {
+          " 'test_lib::TestClass::bar'.", (TestHarness test) {
     var method = new Procedure(
         new Name('bar'),
         ProcedureKind.Method,
@@ -261,7 +261,7 @@
   negativeTest(
       'ConstructorInvocation with missing type argument',
       "ConstructorInvocation with wrong number of type arguments for"
-      " 'test_lib::TestClass::foo'.", (TestHarness test) {
+          " 'test_lib::TestClass::foo'.", (TestHarness test) {
     var class_ = new Class(
         name: 'Test',
         typeParameters: [test.makeTypeParameter()],
@@ -309,7 +309,7 @@
   negativeTest(
       'Invalid typedef Foo = Foo',
       "The typedef 'typedef Foo = test_lib::Foo;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var typedef_ = new Typedef('Foo', null);
     typedef_.type = new TypedefType(typedef_);
     test.addNode(typedef_);
@@ -317,7 +317,7 @@
   negativeTest(
       'Invalid typedef Foo = `(Foo) => void`',
       "The typedef 'typedef Foo = (test_lib::Foo) →* void;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var typedef_ = new Typedef('Foo', null);
     typedef_.type =
         new FunctionType([new TypedefType(typedef_)], const VoidType());
@@ -326,7 +326,7 @@
   negativeTest(
       'Invalid typedef Foo = `() => Foo`',
       "The typedef 'typedef Foo = () →* test_lib::Foo;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var typedef_ = new Typedef('Foo', null);
     typedef_.type = new FunctionType([], new TypedefType(typedef_));
     test.addNode(typedef_);
@@ -334,7 +334,7 @@
   negativeTest(
       'Invalid typedef Foo = C<Foo>',
       "The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Foo>*;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var typedef_ = new Typedef('Foo', null);
     typedef_.type =
         new InterfaceType(test.otherClass, [new TypedefType(typedef_)]);
@@ -343,7 +343,7 @@
   negativeTest(
       'Invalid typedefs Foo = Bar, Bar = Foo',
       "The typedef 'typedef Foo = test_lib::Bar;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var foo = new Typedef('Foo', null);
     var bar = new Typedef('Bar', null);
     foo.type = new TypedefType(bar);
@@ -354,7 +354,7 @@
   negativeTest(
       'Invalid typedefs Foo = Bar, Bar = C<Foo>',
       "The typedef 'typedef Foo = test_lib::Bar;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var foo = new Typedef('Foo', null);
     var bar = new Typedef('Bar', null);
     foo.type = new TypedefType(bar);
@@ -365,7 +365,7 @@
   negativeTest(
       'Invalid typedefs Foo = C<Bar>, Bar = C<Foo>',
       "The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Bar>*;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var foo = new Typedef('Foo', null);
     var bar = new Typedef('Bar', null);
     foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]);
@@ -385,7 +385,7 @@
   negativeTest(
       'Invalid long typedefs C20 = C19 = ... = C1 = C0 = C20',
       "The typedef 'typedef C0 = test_lib::C19;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var typedef_ = new Typedef('C0', null);
     test.enclosingLibrary.addTypedef(typedef_);
     var first = typedef_;
@@ -427,7 +427,7 @@
   negativeTest(
       'Invalid typedefs Foo<T extends Bar<T>>, Bar<T extends Foo<T>>',
       "The typedef 'typedef Foo<T extends test_lib::Bar<T*>> = dynamic;\n'"
-      " refers to itself", (TestHarness test) {
+          " refers to itself", (TestHarness test) {
     var fooParam = test.makeTypeParameter('T');
     var foo =
         new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]);
@@ -443,8 +443,8 @@
   negativeTest(
       'Invalid typedef Foo<T extends Foo<dynamic> = C<T>',
       "The typedef 'typedef Foo<T extends test_lib::Foo<dynamic>> = "
-      "test_lib::OtherClass<T>*;\n'"
-      " refers to itself", (TestHarness test) {
+          "test_lib::OtherClass<T*>*;\n'"
+          " refers to itself", (TestHarness test) {
     var param = new TypeParameter('T', null);
     var foo = new Typedef('Foo',
         new InterfaceType(test.otherClass, [new TypeParameterType(param)]),
@@ -455,7 +455,7 @@
   negativeTest(
       'Typedef arity error',
       "The typedef type test_lib::Foo provides 0 type arguments"
-      " but the typedef declares 1 parameters.", (TestHarness test) {
+          " but the typedef declares 1 parameters.", (TestHarness test) {
     var param = test.makeTypeParameter('T');
     var foo =
         new Typedef('Foo', test.otherClass.rawType, typeParameters: [param]);
@@ -467,7 +467,7 @@
   negativeTest(
       'Dangling typedef reference',
       "Dangling reference to 'typedef Foo = test_lib::OtherClass<dynamic>*;\n'"
-      ", parent is: 'null'", (TestHarness test) {
+          ", parent is: 'null'", (TestHarness test) {
     var foo = new Typedef('Foo', test.otherClass.rawType, typeParameters: []);
     var field = new Field(new Name('field'),
         type: new TypedefType(foo, []), isStatic: true);
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index eefb621..285356d 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -89,8 +89,8 @@
 /// Tools, such as the analyzer, can provide feedback if
 ///
 /// * the annotation is associated with anything other than a method, or
-/// * the annotation is associated with a method that has this annotation that
-///   can return anything other than a newly allocated object or `null`.
+/// * a method that has this annotation can return anything other than a newly
+///   allocated object or `null`.
 const _Factory factory = const _Factory();
 
 /// Used to annotate a class `C`. Indicates that `C` and all subtypes of `C`
@@ -149,10 +149,10 @@
 ///   without invoking the overridden method.
 const _MustCallSuper mustCallSuper = const _MustCallSuper();
 
-/// Used to annotate a class declaration `C`. Indicates that any type arguments
-/// declared on `C` are to be treated as optional.  Tools such as the analyzer
-/// and linter can use this information to suppress warnings that would
-/// otherwise require type arguments to be provided for instances of `C`.
+/// Used to annotate a class, mixin, or extension declaration `C`. Indicates
+/// that any type arguments declared on `C` are to be treated as optional.
+/// Tools such as the analyzer and linter can use this information to suppress
+/// warnings that would otherwise require type arguments on `C` to be provided.
 const _OptionalTypeArgs optionalTypeArgs = const _OptionalTypeArgs();
 
 /// Used to annotate an instance member (method, getter, setter, operator, or
@@ -168,9 +168,10 @@
 /// * the annotation is associated with anything other than an instance member,
 ///   or
 /// * an invocation of a member that has this annotation is used outside of an
-///   instance member defined on a class that extends or mixes in the class in
-///   which the protected member is defined, or that uses a receiver other than
-///   `this`.
+///   instance member defined on a class that extends or mixes in (or a mixin
+///   constrained to) the class in which the protected member is defined.
+/// * an invocation of a member that has this annotation is used within an
+///   instance method, but the receiver is something other than `this`.
 const _Protected protected = const _Protected();
 
 /// Used to annotate a named parameter `p` in a method or function `f`.
@@ -216,7 +217,7 @@
 /// Tools, such as the analyzer, can provide feedback if
 ///
 /// * the annotation is associated with a declaration other than a public
-///   instance member in a class, or
+///   instance member in a class or mixin, or
 /// * the member is referenced outside of the defining library.
 const _VisibleForOverriding visibleForOverriding =
     const _VisibleForOverriding();
@@ -227,7 +228,8 @@
 /// Tools, such as the analyzer, can provide feedback if
 ///
 /// * the annotation is associated with a declaration not in the `lib` folder
-///   of a package, or
+///   of a package, or a private declaration, or a declaration in an unnamed
+///   static extension, or
 /// * the declaration is referenced outside of its the defining library or a
 ///   library which is in the `test` folder of the defining package.
 const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
@@ -240,7 +242,7 @@
   final String reason;
 
   /// Initialize a newly created instance to have the given [reason].
-  const Immutable([this.reason]);
+  const Immutable([this.reason = '']);
 }
 
 /// Used to annotate a named parameter `p` in a method or function `f`.
@@ -259,7 +261,7 @@
   final String reason;
 
   /// Initialize a newly created instance to have the given [reason].
-  const Required([this.reason]);
+  const Required([this.reason = '']);
 }
 
 class _AlwaysThrows {
diff --git a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
index a01cb83..f34d762 100644
--- a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
+++ b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.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/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
 import 'package:nnbd_migration/src/decorated_type.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
 
@@ -13,7 +15,9 @@
 class AlreadyMigratedCodeDecorator {
   final NullabilityGraph _graph;
 
-  AlreadyMigratedCodeDecorator(this._graph);
+  final TypeProvider _typeProvider;
+
+  AlreadyMigratedCodeDecorator(this._graph, this._typeProvider);
 
   /// Transforms [type], which should have come from code that has already been
   /// migrated to NNBD, into the corresponding [DecoratedType].
@@ -21,12 +25,10 @@
     if (type.isVoid || type.isDynamic) {
       return DecoratedType(type, _graph.always);
     }
+    NullabilityNode node;
     var nullabilitySuffix = (type as TypeImpl).nullabilitySuffix;
     if (nullabilitySuffix == NullabilitySuffix.question) {
-      // TODO(paulberry): add support for depending on already-migrated packages
-      // containing nullable types.
-      throw UnimplementedError(
-          'Migration depends on an already-migrated nullable type');
+      node = _graph.always;
     } else {
       // Currently, all types passed to this method have nullability suffix `star`
       // because (a) we don't yet have a migrated SDK, and (b) we haven't added
@@ -34,11 +36,18 @@
       // migrated with NNBD enabled.
       // TODO(paulberry): fix this assertion when things change.
       assert(nullabilitySuffix == NullabilitySuffix.star);
+      node = _graph.never;
     }
     if (type is FunctionType) {
-      if (type.typeFormals.isNotEmpty) {
-        throw UnimplementedError('Decorating generic function type');
-      }
+      var typeFormalBounds = type.typeFormals.map((e) {
+        var bound = e.bound;
+        if (bound == null) {
+          return decorate((_typeProvider.objectType as TypeImpl)
+              .withNullability(NullabilitySuffix.question));
+        } else {
+          return decorate(bound);
+        }
+      }).toList();
       var positionalParameters = <DecoratedType>[];
       var namedParameters = <String, DecoratedType>{};
       for (var parameter in type.parameters) {
@@ -48,23 +57,44 @@
           namedParameters[parameter.name] = decorate(parameter.type);
         }
       }
-      return DecoratedType(type, _graph.never,
+      return DecoratedType(type, node,
+          typeFormalBounds: typeFormalBounds,
           returnType: decorate(type.returnType),
           namedParameters: namedParameters,
           positionalParameters: positionalParameters);
     } else if (type is InterfaceType) {
       if (type.typeParameters.isNotEmpty) {
         assert(type.typeArguments.length == type.typeParameters.length);
-        return DecoratedType(type, _graph.never,
+        return DecoratedType(type, node,
             typeArguments: type.typeArguments.map(decorate).toList());
       }
-      return DecoratedType(type, _graph.never);
+      return DecoratedType(type, node);
     } else if (type is TypeParameterType) {
-      return DecoratedType(type, _graph.never);
+      return DecoratedType(type, node);
     } else {
       // TODO(paulberry)
       throw UnimplementedError(
           'Unable to decorate already-migrated type $type');
     }
   }
+
+  /// Get all the decorated immediate supertypes of the non-migrated class
+  /// [class_].
+  Iterable<DecoratedType> getImmediateSupertypes(ClassElement class_) {
+    var allSupertypes = <DartType>[];
+    var supertype = class_.supertype;
+    if (supertype != null) {
+      allSupertypes.add(supertype);
+    }
+    allSupertypes.addAll(class_.superclassConstraints);
+    allSupertypes.addAll(class_.interfaces);
+    allSupertypes.addAll(class_.mixins);
+    var type = class_.type;
+    if (type.isDartAsyncFuture) {
+      // Add FutureOr<T> as a supertype of Future<T>.
+      allSupertypes
+          .add(_typeProvider.futureOrType.instantiate(type.typeArguments));
+    }
+    return allSupertypes.map(decorate);
+  }
 }
diff --git a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
index 40a4d8d..8c46c9e 100644
--- a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:nnbd_migration/src/decorated_type.dart';
 import 'package:nnbd_migration/src/node_builder.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
@@ -26,26 +25,6 @@
 
   DecoratedClassHierarchy(this._variables, this._graph);
 
-  /// Retrieves a [DecoratedType] describing how [class_] implements
-  /// [superclass].
-  ///
-  /// If [class_] does not implement [superclass], raises an exception.
-  ///
-  /// Note that the returned [DecoratedType] will have a node of `never`,
-  /// because the relationship between a class and its superclass is not
-  /// nullable.
-  DecoratedType getDecoratedSupertype(
-      ClassElement class_, ClassElement superclass) {
-    assert(!(class_.library.isDartCore && class_.name == 'Null'));
-    assert(class_ is! ClassElementHandle);
-    assert(superclass is! ClassElementHandle);
-    if (superclass.typeParameters.isEmpty) {
-      return DecoratedType(superclass.type, _graph.never);
-    }
-    return _getGenericSupertypeDecorations(class_)[superclass] ??
-        (throw StateError('Unrelated types'));
-  }
-
   /// Retrieves a [DecoratedType] describing how [type] implements [superclass].
   ///
   /// If [type] is not an interface type, or it does not implement [superclass],
@@ -62,6 +41,24 @@
     return result.withNode(type.node);
   }
 
+  /// Retrieves a [DecoratedType] describing how [class_] implements
+  /// [superclass].
+  ///
+  /// If [class_] does not implement [superclass], raises an exception.
+  ///
+  /// Note that the returned [DecoratedType] will have a node of `never`,
+  /// because the relationship between a class and its superclass is not
+  /// nullable.
+  DecoratedType getDecoratedSupertype(
+      ClassElement class_, ClassElement superclass) {
+    assert(!(class_.library.isDartCore && class_.name == 'Null'));
+    if (superclass.typeParameters.isEmpty) {
+      return DecoratedType(superclass.type, _graph.never);
+    }
+    return _getGenericSupertypeDecorations(class_)[superclass] ??
+        (throw StateError('Unrelated types: $class_ and $superclass'));
+  }
+
   /// Computes a map whose keys are all the superclasses of [class_], and whose
   /// values indicate how [class_] implements each superclass.
   Map<ClassElement, DecoratedType> _getGenericSupertypeDecorations(
@@ -70,7 +67,7 @@
     if (decorations == null) {
       // Call ourselves recursively to compute how each of [class_]'s direct
       // superclasses relates to all of its transitive superclasses.
-      decorations = _genericSupertypeDecorations[class_] = {};
+      decorations = {};
       var decoratedDirectSupertypes =
           _variables.decoratedDirectSupertypes(class_);
       for (var entry in decoratedDirectSupertypes.entries) {
@@ -96,6 +93,7 @@
         // superclass.
         decorations[superclass] ??= decoratedSupertype;
       }
+      _genericSupertypeDecorations[class_] = decorations;
     }
     return decorations;
   }
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 1480f7e..9982d1f 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -70,7 +70,7 @@
         for (int i = 0; i < typeFormalBounds.length; i++) {
           var declaredBound = type.typeFormals[i].bound;
           if (declaredBound == null) {
-            assert(typeFormalBounds[i].type.isDartCoreObject);
+            assert(typeFormalBounds[i].type.toString() == 'Object');
           } else {
             assert(typeFormalBounds[i].type == declaredBound);
           }
@@ -140,20 +140,38 @@
   /// nodes everywhere that don't correspond to any source location.  These
   /// nodes can later be unioned with other nodes.
   factory DecoratedType.forImplicitType(
-      TypeProvider typeProvider, DartType type, NullabilityGraph graph) {
+      TypeProvider typeProvider, DartType type, NullabilityGraph graph,
+      {List<DecoratedType> typeArguments}) {
     if (type.isDynamic || type.isVoid) {
+      assert(typeArguments == null);
       return DecoratedType(type, graph.always);
     } else if (type is InterfaceType) {
+      assert(() {
+        if (typeArguments != null) {
+          assert(typeArguments.length == type.typeArguments.length);
+          for (var i = 0; i < typeArguments.length; ++i) {
+            assert(typeArguments[i].type == type.typeArguments[i]);
+          }
+        }
+        return true;
+      }());
+
+      typeArguments ??= type.typeArguments
+          .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph))
+          .toList();
       return DecoratedType(type, NullabilityNode.forInferredType(),
-          typeArguments: type.typeArguments
-              .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph))
-              .toList());
+          typeArguments: typeArguments);
     } else if (type is FunctionType) {
+      if (typeArguments != null) {
+        throw "Not supported: implicit function type with explicit type arguments";
+      }
       return DecoratedType.forImplicitFunction(
           typeProvider, type, NullabilityNode.forInferredType(), graph);
     } else if (type is TypeParameterType) {
+      assert(typeArguments == null);
       return DecoratedType(type, NullabilityNode.forInferredType());
     } else if (type is BottomTypeImpl) {
+      assert(typeArguments == null);
       return DecoratedType(type, NullabilityNode.forInferredType());
     }
     // TODO(paulberry)
@@ -163,8 +181,7 @@
 
   /// Creates a [DecoratedType] for a synthetic type parameter, to be used
   /// during comparison of generic function types.
-  DecoratedType._forTypeParameterSubstitution(
-      TypeParameterElementImpl parameter)
+  DecoratedType._forTypeParameterSubstitution(TypeParameterElement parameter)
       : type = TypeParameterTypeImpl(parameter),
         node = null,
         returnType = null,
@@ -290,6 +307,7 @@
   DecoratedType instantiate(List<DecoratedType> argumentTypes) {
     var type = this.type as FunctionType;
     var typeFormals = type.typeFormals;
+    assert(argumentTypes.length == typeFormals.length);
     List<DartType> undecoratedArgumentTypes = [];
     Map<TypeParameterElement, DecoratedType> substitution = {};
     for (int i = 0; i < argumentTypes.length; i++) {
@@ -323,7 +341,7 @@
 
   @override
   String toString() {
-    var trailing = node.debugSuffix;
+    var trailing = node == null ? '' : node.debugSuffix;
     var type = this.type;
     if (type is TypeParameterType || type is VoidType) {
       return '$type$trailing';
@@ -382,8 +400,27 @@
       DartType undecoratedResult) {
     var type = this.type;
     if (type is FunctionType && undecoratedResult is FunctionType) {
-      assert(type.typeFormals.isEmpty); // TODO(paulberry)
-      return _substituteFunctionAfterFormals(undecoratedResult, substitution);
+      var typeFormals = type.typeFormals;
+      assert(typeFormals.length == undecoratedResult.typeFormals.length);
+      var newTypeFormalBounds = <DecoratedType>[];
+      if (typeFormals.isNotEmpty) {
+        // The analyzer sometimes allocates fresh type variables when performing
+        // substitutions, so we need to reflect that in our decorations by
+        // substituting to use the type variables the analyzer used.
+        substitution =
+            Map<TypeParameterElement, DecoratedType>.from(substitution);
+        for (int i = 0; i < typeFormals.length; i++) {
+          substitution[typeFormals[i]] =
+              DecoratedType._forTypeParameterSubstitution(
+                  undecoratedResult.typeFormals[i]);
+        }
+        for (int i = 0; i < typeFormalBounds.length; i++) {
+          newTypeFormalBounds.add(typeFormalBounds[i]._substitute(
+              substitution, typeFormals[i].bound ?? typeFormalBounds[i].type));
+        }
+      }
+      return _substituteFunctionAfterFormals(undecoratedResult, substitution,
+          newTypeFormalBounds: newTypeFormalBounds);
     } else if (type is InterfaceType && undecoratedResult is InterfaceType) {
       List<DecoratedType> newTypeArguments = [];
       for (int i = 0; i < typeArguments.length; i++) {
@@ -400,10 +437,10 @@
         return inner
             .withNode(NullabilityNode.forSubstitution(inner.node, node));
       }
-    } else if (type is VoidType) {
+    } else if (type.isVoid || type.isDynamic) {
       return this;
     }
-    throw '$type.substitute($substitution)'; // TODO(paulberry)
+    throw '$type.substitute($type | $substitution)'; // TODO(paulberry)
   }
 
   /// Performs the logic that is common to substitution and function type
@@ -411,20 +448,31 @@
   /// is [undecoratedResult], and whose return type, positional parameters, and
   /// named parameters are formed by performing the given [substitution].
   DecoratedType _substituteFunctionAfterFormals(FunctionType undecoratedResult,
-      Map<TypeParameterElement, DecoratedType> substitution) {
+      Map<TypeParameterElement, DecoratedType> substitution,
+      {List<DecoratedType> newTypeFormalBounds = const []}) {
     var newPositionalParameters = <DecoratedType>[];
+    var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
     for (int i = 0; i < positionalParameters.length; i++) {
-      var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
       var undecoratedParameterType = i < numRequiredParameters
           ? undecoratedResult.normalParameterTypes[i]
           : undecoratedResult.optionalParameterTypes[i - numRequiredParameters];
       newPositionalParameters.add(positionalParameters[i]
           ._substitute(substitution, undecoratedParameterType));
     }
+    var newNamedParameters = <String, DecoratedType>{};
+    for (var entry in namedParameters.entries) {
+      var name = entry.key;
+      var undecoratedParameterType =
+          undecoratedResult.namedParameterTypes[name];
+      newNamedParameters[name] =
+          (entry.value._substitute(substitution, undecoratedParameterType));
+    }
     return DecoratedType(undecoratedResult, node,
+        typeFormalBounds: newTypeFormalBounds,
         returnType:
             returnType._substitute(substitution, undecoratedResult.returnType),
-        positionalParameters: newPositionalParameters);
+        positionalParameters: newPositionalParameters,
+        namedParameters: newNamedParameters);
   }
 
   List<DecoratedType> _substituteList(List<DecoratedType> list,
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index d6bdee5..5a73336 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -37,6 +37,9 @@
   @override
   final TypeSystem _typeSystem;
 
+  @override
+  final TypeProvider _typeProvider;
+
   final NullabilityGraph _graph;
 
   /// Tests should fill in this map with the bounds of any type parameters being
@@ -46,8 +49,8 @@
   @override
   final DecoratedClassHierarchy _decoratedClassHierarchy;
 
-  AssignmentCheckerForTesting(
-      this._typeSystem, this._graph, this._decoratedClassHierarchy);
+  AssignmentCheckerForTesting(this._typeSystem, this._typeProvider, this._graph,
+      this._decoratedClassHierarchy);
 
   void checkAssignment(EdgeOrigin origin,
       {@required DecoratedType source,
@@ -95,6 +98,8 @@
 
   final NullabilityGraph _graph;
 
+  TypeProvider _typeProvider;
+
   @override
   final Source source;
 
@@ -122,6 +127,9 @@
   /// For convenience, a [DecoratedType] representing `Null`.
   final DecoratedType _nullType;
 
+  /// For convenience, a [DecoratedType] representing `dynamic`.
+  final DecoratedType _dynamicType;
+
   /// The [DecoratedType] of the innermost function or method being visited, or
   /// `null` if the visitor is not inside any function or method.
   ///
@@ -130,11 +138,25 @@
   DecoratedType _currentFunctionType;
 
   /// The [DecoratedType] of the innermost list or set literal being visited, or
-  /// `null` if the visitor is not inside any function or method.
+  /// `null` if the visitor is not inside any list or set.
   ///
   /// This is needed to construct the appropriate nullability constraints for
-  /// ui as code list elements.
-  DecoratedType _currentLiteralType;
+  /// ui as code elements.
+  DecoratedType _currentLiteralElementType;
+
+  /// The key [DecoratedType] of the innermost map literal being visited, or
+  /// `null` if the visitor is not inside any map.
+  ///
+  /// This is needed to construct the appropriate nullability constraints for
+  /// ui as code elements.
+  DecoratedType _currentMapKeyType;
+
+  /// The value [DecoratedType] of the innermost map literal being visited, or
+  /// `null` if the visitor is not inside any map.
+  ///
+  /// This is needed to construct the appropriate nullability constraints for
+  /// ui as code elements.
+  DecoratedType _currentMapValueType;
 
   /// Information about the most recently visited binary expression whose
   /// boolean value could possibly affect nullability analysis.
@@ -164,41 +186,33 @@
   /// nullable.
   final Map<Expression, NullabilityNode> _conditionalNodes = {};
 
-  EdgeBuilder(TypeProvider typeProvider, this._typeSystem, this._variables,
+  List<String> _objectGetNames;
+
+  EdgeBuilder(this._typeProvider, this._typeSystem, this._variables,
       this._graph, this.source, this.listener)
       : _decoratedClassHierarchy = DecoratedClassHierarchy(_variables, _graph),
         _inheritanceManager = InheritanceManager3(_typeSystem),
-        _notNullType = DecoratedType(typeProvider.objectType, _graph.never),
+        _notNullType = DecoratedType(_typeProvider.objectType, _graph.never),
         _nonNullableBoolType =
-            DecoratedType(typeProvider.boolType, _graph.never),
+            DecoratedType(_typeProvider.boolType, _graph.never),
         _nonNullableTypeType =
-            DecoratedType(typeProvider.typeType, _graph.never),
-        _nullType = DecoratedType(typeProvider.nullType, _graph.always);
+            DecoratedType(_typeProvider.typeType, _graph.never),
+        _nullType = DecoratedType(_typeProvider.nullType, _graph.always),
+        _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always);
 
   /// Gets the decorated type of [element] from [_variables], performing any
   /// necessary substitutions.
   DecoratedType getOrComputeElementType(Element element,
       {DecoratedType targetType}) {
     Map<TypeParameterElement, DecoratedType> substitution;
-    Element baseElement;
-    if (element is Member) {
-      assert(targetType != null);
-      baseElement = element.baseElement;
-      var targetTypeType = targetType.type;
-      if (targetTypeType is InterfaceType &&
-          baseElement is ClassMemberElement) {
-        var enclosingClass = baseElement.enclosingElement as ClassElement;
-        assert(targetTypeType.element == enclosingClass); // TODO(paulberry)
-        substitution = <TypeParameterElement, DecoratedType>{};
-        assert(enclosingClass.typeParameters.length ==
-            targetTypeType.typeArguments.length); // TODO(paulberry)
-        for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
-          substitution[enclosingClass.typeParameters[i]] =
-              targetType.typeArguments[i];
-        }
+    Element baseElement = element is Member ? element.baseElement : element;
+    if (targetType != null) {
+      var classElement = baseElement.enclosingElement as ClassElement;
+      if (classElement.typeParameters.isNotEmpty) {
+        substitution = _decoratedClassHierarchy
+            .asInstanceOf(targetType, classElement)
+            .asSubstitution;
       }
-    } else {
-      baseElement = element;
     }
     DecoratedType decoratedBaseType;
     if (baseElement is PropertyAccessorElement &&
@@ -224,6 +238,8 @@
         elementType = element.type;
       } else if (element is ConstructorElement) {
         elementType = element.type;
+      } else if (element is PropertyAccessorMember) {
+        elementType = element.type;
       } else {
         throw element.runtimeType; // TODO(paulberry)
       }
@@ -235,8 +251,9 @@
 
   @override
   DecoratedType visitAsExpression(AsExpression node) {
-    // TODO(brianwilkerson)
-    _unimplemented(node, 'AsExpression');
+    final typeNode = _variables.decoratedTypeAnnotation(source, node.type);
+    _handleAssignment(node.expression, destinationType: typeNode);
+    return typeNode;
   }
 
   @override
@@ -256,13 +273,16 @@
 
   @override
   DecoratedType visitAssignmentExpression(AssignmentExpression node) {
-    if (node.operator.type != TokenType.EQ) {
-      // TODO(paulberry)
-      _unimplemented(node, 'Assignment with operator ${node.operator.lexeme}');
+    _CompoundOperatorInfo compoundOperatorInfo;
+    if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+      _unimplemented(node, 'Assignment with operator ??=');
+    } else if (node.operator.type != TokenType.EQ) {
+      compoundOperatorInfo = _CompoundOperatorInfo(
+          node.staticElement, node.operator.offset, node.staticType);
     }
-    _postDominatedLocals.removeReferenceFromAllScopes(node.leftHandSide);
     var expressionType = _handleAssignment(node.rightHandSide,
-        destinationExpression: node.leftHandSide);
+        destinationExpression: node.leftHandSide,
+        compoundOperatorInfo: compoundOperatorInfo);
     var conditionalNode = _conditionalNodes[node.leftHandSide];
     if (conditionalNode != null) {
       expressionType = expressionType.withNode(
@@ -325,14 +345,19 @@
     } else if (operatorType == TokenType.QUESTION_QUESTION) {
       DecoratedType expressionType;
       var leftType = node.leftOperand.accept(this);
+      _flowAnalysis.ifNullExpression_rightBegin();
       try {
         _guards.add(leftType.node);
-        var rightType = node.rightOperand.accept(this);
+        DecoratedType rightType;
+        _postDominatedLocals.doScoped(action: () {
+          rightType = node.rightOperand.accept(this);
+        });
         var ifNullNode = NullabilityNode.forIfNotNull();
         expressionType = DecoratedType(node.staticType, ifNullNode);
         _connect(rightType.node, expressionType.node,
             IfNullOrigin(source, node.offset));
       } finally {
+        _flowAnalysis.ifNullExpression_end();
         _guards.removeLast();
       }
       _variables.recordDecoratedExpressionType(node, expressionType);
@@ -387,6 +412,7 @@
 
   @override
   DecoratedType visitCatchClause(CatchClause node) {
+    _flowAnalysis.tryCatchStatement_catchBegin();
     node.exceptionType?.accept(this);
     for (var identifier in [
       node.exceptionParameter,
@@ -397,7 +423,10 @@
             assigned: true);
       }
     }
-    node.body.accept(this);
+    // The catch clause may not execute, so create a new scope for
+    // post-dominators.
+    _postDominatedLocals.doScoped(action: () => node.body.accept(this));
+    _flowAnalysis.tryCatchStatement_catchEnd();
     return null;
   }
 
@@ -523,7 +552,8 @@
 
   @override
   DecoratedType visitDoStatement(DoStatement node) {
-    _flowAnalysis.doStatement_bodyBegin(node, _assignedVariables[node]);
+    _flowAnalysis.doStatement_bodyBegin(
+        node, _assignedVariables.writtenInNode(node));
     node.body.accept(this);
     _flowAnalysis.doStatement_conditionBegin();
     _checkExpressionNotNull(node.condition);
@@ -580,13 +610,15 @@
 
   @override
   DecoratedType visitForElement(ForElement node) {
-    _handleForLoopParts(node, node.forLoopParts, node.body);
+    _handleForLoopParts(node, node.forLoopParts, node.body,
+        (body) => _handleCollectionElement(body as CollectionElement));
     return null;
   }
 
   @override
   DecoratedType visitForStatement(ForStatement node) {
-    _handleForLoopParts(node, node.forLoopParts, node.body);
+    _handleForLoopParts(
+        node, node.forLoopParts, node.body, (body) => body.accept(this));
     return null;
   }
 
@@ -632,7 +664,7 @@
       FunctionExpressionInvocation node) {
     DecoratedType calleeType = node.function.accept(this);
     return _handleInvocationArguments(node, node.argumentList.arguments,
-        node.typeArguments, calleeType, null);
+        node.typeArguments, node.typeArgumentTypes, calleeType, null);
   }
 
   @override
@@ -726,8 +758,10 @@
     }
     var callee = node.staticElement;
     if (callee == null) {
-      // TODO(paulberry)
-      _unimplemented(node, 'Index expression with no static type');
+      // Dynamic dispatch.  The return type is `dynamic`.
+      // TODO(paulberry): would it be better to assume a return type of `Never`
+      // so that we don't unnecessarily propagate nullabilities everywhere?
+      return _dynamicType;
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     // TODO(paulberry): substitute if necessary
@@ -745,20 +779,32 @@
       InstanceCreationExpression node) {
     var callee = node.staticElement;
     var typeParameters = callee.enclosingElement.typeParameters;
+    List<DartType> typeArgumentTypes;
     List<DecoratedType> decoratedTypeArguments;
     var typeArguments = node.constructorName.type.typeArguments;
     if (typeArguments != null) {
+      typeArgumentTypes = typeArguments.arguments.map((t) => t.type).toList();
       decoratedTypeArguments = typeArguments.arguments
           .map((t) => _variables.decoratedTypeAnnotation(source, t))
           .toList();
     } else {
-      decoratedTypeArguments = const [];
+      var staticType = node.staticType;
+      if (staticType is InterfaceType) {
+        typeArgumentTypes = staticType.typeArguments;
+        decoratedTypeArguments = typeArgumentTypes
+            .map((t) => DecoratedType.forImplicitType(_typeProvider, t, _graph))
+            .toList();
+      } else {
+        // Note: this could happen if the code being migrated has errors.
+        typeArgumentTypes = const [];
+        decoratedTypeArguments = const [];
+      }
     }
     var createdType = DecoratedType(node.staticType, _graph.never,
         typeArguments: decoratedTypeArguments);
     var calleeType = getOrComputeElementType(callee, targetType: createdType);
     _handleInvocationArguments(node, node.argumentList.arguments, typeArguments,
-        calleeType, typeParameters);
+        typeArgumentTypes, calleeType, typeParameters);
     return createdType;
   }
 
@@ -792,42 +838,42 @@
 
   @override
   DecoratedType visitLibraryDirective(LibraryDirective node) {
-    // skip directives
+    // skip directives, but not their metadata
+    node.metadata.accept(this);
     return null;
   }
 
   @override
   DecoratedType visitListLiteral(ListLiteral node) {
-    var listType = node.staticType as InterfaceType;
-    if (node.typeArguments == null) {
-      // TODO(brianwilkerson) We might want to create a fake node in the graph
-      //  to represent the type argument so that we can still create edges from
-      //  the elements to it.
-      // TODO(brianwilkerson)
-      _unimplemented(node, 'List literal with no type arguments');
-    } else {
-      var typeArgumentType = _variables.decoratedTypeAnnotation(
-          source, node.typeArguments.arguments[0]);
-      if (typeArgumentType == null) {
-        _unimplemented(node, 'Could not compute type argument type');
+    final previousLiteralType = _currentLiteralElementType;
+    try {
+      var listType = node.staticType as InterfaceType;
+      if (node.typeArguments == null) {
+        _currentLiteralElementType = DecoratedType.forImplicitType(
+            _typeProvider, listType.typeArguments[0], _graph);
+      } else {
+        _currentLiteralElementType = _variables.decoratedTypeAnnotation(
+            source, node.typeArguments.arguments[0]);
       }
-      final previousLiteralType = _currentLiteralType;
-      try {
-        _currentLiteralType = typeArgumentType;
-        node.elements.forEach(_handleCollectionElement);
-      } finally {
-        _currentLiteralType = previousLiteralType;
-      }
+      node.elements.forEach(_handleCollectionElement);
       return DecoratedType(listType, _graph.never,
-          typeArguments: [typeArgumentType]);
+          typeArguments: [_currentLiteralElementType]);
+    } finally {
+      _currentLiteralElementType = previousLiteralType;
     }
   }
 
   @override
+  DecoratedType visitMapLiteralEntry(MapLiteralEntry node) {
+    assert(_currentMapKeyType != null);
+    assert(_currentMapValueType != null);
+    _handleAssignment(node.key, destinationType: _currentMapKeyType);
+    _handleAssignment(node.value, destinationType: _currentMapValueType);
+    return null;
+  }
+
+  @override
   DecoratedType visitMethodDeclaration(MethodDeclaration node) {
-    if (node.typeParameters != null) {
-      _unimplemented(node, 'Generic method');
-    }
     _handleExecutableDeclaration(node, node.declaredElement, node.metadata,
         node.returnType, node.parameters, null, node.body, null);
     return null;
@@ -838,25 +884,37 @@
     DecoratedType targetType;
     var target = node.realTarget;
     bool isConditional = _isConditionalExpression(node);
+    var callee = node.methodName.staticElement;
+    bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
     if (target != null) {
-      if (isConditional) {
+      if (_isPrefix(target)) {
+        // Nothing to do.
+      } else if (calleeIsStatic) {
+        target.accept(this);
+      } else if (isConditional) {
         targetType = target.accept(this);
       } else {
-        _checkNonObjectMember(node.methodName.name); // TODO(paulberry)
-        targetType = _checkExpressionNotNull(target);
+        targetType = _handleTarget(target, node.methodName.name);
       }
     }
-    var callee = node.methodName.staticElement;
     if (callee == null) {
-      // TODO(paulberry)
-      _unimplemented(node, 'Unresolved method name');
+      // Dynamic dispatch.  The return type is `dynamic`.
+      // TODO(paulberry): would it be better to assume a return type of `Never`
+      // so that we don't unnecessarily propagate nullabilities everywhere?
+      return _dynamicType;
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     if (callee is PropertyAccessorElement) {
       calleeType = calleeType.returnType;
     }
-    var expressionType = _handleInvocationArguments(node,
-        node.argumentList.arguments, node.typeArguments, calleeType, null);
+    var expressionType = _handleInvocationArguments(
+        node,
+        node.argumentList.arguments,
+        node.typeArguments,
+        node.typeArgumentTypes,
+        calleeType,
+        null,
+        invokeType: node.staticInvokeType);
     if (isConditional) {
       expressionType = expressionType.withNode(
           NullabilityNode.forLUB(targetType.node, expressionType.node));
@@ -867,7 +925,8 @@
 
   @override
   DecoratedType visitNamespaceDirective(NamespaceDirective node) {
-    // skip directives
+    // skip directives, but not their metadata
+    node.metadata.accept(this);
     return null;
   }
 
@@ -882,6 +941,13 @@
   }
 
   @override
+  DecoratedType visitPartOfDirective(PartOfDirective node) {
+    // skip directives, but not their metadata
+    node.metadata.accept(this);
+    return null;
+  }
+
+  @override
   DecoratedType visitPostfixExpression(PostfixExpression node) {
     var operatorType = node.operator.type;
     if (operatorType == TokenType.PLUS_PLUS ||
@@ -921,6 +987,7 @@
     var targetType = _checkExpressionNotNull(node.operand);
     var operatorType = node.operator.type;
     if (operatorType == TokenType.BANG) {
+      _flowAnalysis.logicalNot_end(node, node.operand);
       return _nonNullableBoolType;
     } else if (operatorType == TokenType.PLUS_PLUS ||
         operatorType == TokenType.MINUS_MINUS) {
@@ -941,7 +1008,7 @@
     } else {
       var callee = node.staticElement;
       var calleeType = getOrComputeElementType(callee, targetType: targetType);
-      return _handleInvocationArguments(node, [], null, calleeType, null);
+      return _handleInvocationArguments(node, [], null, null, calleeType, null);
     }
   }
 
@@ -956,11 +1023,17 @@
     var callee = node.staticElement;
     var calleeType = _variables.decoratedElementType(callee);
     _handleInvocationArguments(
-        node, node.argumentList.arguments, null, calleeType, null);
+        node, node.argumentList.arguments, null, null, calleeType, null);
     return null;
   }
 
   @override
+  DecoratedType visitRethrowExpression(RethrowExpression node) {
+    _flowAnalysis.handleExit();
+    return DecoratedType(node.staticType, _graph.never);
+  }
+
+  @override
   DecoratedType visitReturnStatement(ReturnStatement node) {
     DecoratedType returnType = _currentFunctionType.returnType;
     Expression returnValue = node.expression;
@@ -990,51 +1063,54 @@
 
   @override
   DecoratedType visitSetOrMapLiteral(SetOrMapLiteral node) {
-    var listType = node.staticType as InterfaceType;
+    var setOrMapType = node.staticType as InterfaceType;
     var typeArguments = node.typeArguments?.arguments;
-    if (typeArguments == null) {
-      // TODO(brianwilkerson) We might want to create fake nodes in the graph to
-      //  represent the type arguments so that we can still create edges from
-      //  the elements to them.
-      // TODO(brianwilkerson)
-      _unimplemented(node, 'Set or map literal with no type arguments');
-    } else if (typeArguments.length == 1) {
-      var elementType =
-          _variables.decoratedTypeAnnotation(source, typeArguments[0]);
-      for (var element in node.elements) {
-        if (element is Expression) {
-          _handleAssignment(element, destinationType: elementType);
+
+    if (node.isSet) {
+      final previousLiteralType = _currentLiteralElementType;
+      try {
+        if (typeArguments == null) {
+          assert(setOrMapType.typeArguments.length == 1);
+          _currentLiteralElementType = DecoratedType.forImplicitType(
+              _typeProvider, setOrMapType.typeArguments[0], _graph);
         } else {
-          // Handle spread and control flow elements.
-          element.accept(this);
-          // TODO(brianwilkerson)
-          _unimplemented(node, 'Spread or control flow element');
+          assert(typeArguments.length == 1);
+          _currentLiteralElementType =
+              _variables.decoratedTypeAnnotation(source, typeArguments[0]);
         }
+        node.elements.forEach(_handleCollectionElement);
+        return DecoratedType(setOrMapType, _graph.never,
+            typeArguments: [_currentLiteralElementType]);
+      } finally {
+        _currentLiteralElementType = previousLiteralType;
       }
-      return DecoratedType(listType, _graph.never,
-          typeArguments: [elementType]);
-    } else if (typeArguments.length == 2) {
-      var keyType =
-          _variables.decoratedTypeAnnotation(source, typeArguments[0]);
-      var valueType =
-          _variables.decoratedTypeAnnotation(source, typeArguments[1]);
-      for (var element in node.elements) {
-        if (element is MapLiteralEntry) {
-          _handleAssignment(element.key, destinationType: keyType);
-          _handleAssignment(element.value, destinationType: valueType);
-        } else {
-          // Handle spread and control flow elements.
-          element.accept(this);
-          // TODO(brianwilkerson)
-          _unimplemented(node, 'Spread or control flow element');
-        }
-      }
-      return DecoratedType(listType, _graph.never,
-          typeArguments: [keyType, valueType]);
     } else {
-      // TODO(brianwilkerson)
-      _unimplemented(
-          node, 'Set or map literal with more than two type arguments');
+      assert(node.isMap);
+
+      final previousKeyType = _currentMapKeyType;
+      final previousValueType = _currentMapValueType;
+      try {
+        if (typeArguments == null) {
+          assert(setOrMapType.typeArguments.length == 2);
+          _currentMapKeyType = DecoratedType.forImplicitType(
+              _typeProvider, setOrMapType.typeArguments[0], _graph);
+          _currentMapValueType = DecoratedType.forImplicitType(
+              _typeProvider, setOrMapType.typeArguments[1], _graph);
+        } else {
+          assert(typeArguments.length == 2);
+          _currentMapKeyType =
+              _variables.decoratedTypeAnnotation(source, typeArguments[0]);
+          _currentMapValueType =
+              _variables.decoratedTypeAnnotation(source, typeArguments[1]);
+        }
+
+        node.elements.forEach(_handleCollectionElement);
+        return DecoratedType(setOrMapType, _graph.never,
+            typeArguments: [_currentMapKeyType, _currentMapValueType]);
+      } finally {
+        _currentMapKeyType = previousKeyType;
+        _currentMapValueType = previousValueType;
+      }
     }
   }
 
@@ -1055,7 +1131,7 @@
       return staticElement.isGetter
           ? elementType.returnType
           : elementType.positionalParameters[0];
-    } else if (staticElement is ClassElement) {
+    } else if (staticElement is TypeDefiningElement) {
       return _nonNullableTypeType;
     } else {
       // TODO(paulberry)
@@ -1065,6 +1141,42 @@
   }
 
   @override
+  DecoratedType visitSpreadElement(SpreadElement node) {
+    final spreadType = node.expression.staticType;
+    if (_typeSystem.isSubtypeOf(
+        spreadType, _typeProvider.mapObjectObjectType)) {
+      assert(_currentMapKeyType != null && _currentMapValueType != null);
+      final expectedType = _typeSystem.instantiateType(_typeProvider.mapType,
+          [_currentMapKeyType.type, _currentMapValueType.type]);
+      final expectedDecoratedType = DecoratedType.forImplicitType(
+          _typeProvider, expectedType, _graph,
+          typeArguments: [_currentMapKeyType, _currentMapValueType]);
+
+      _handleAssignment(node.expression,
+          destinationType: expectedDecoratedType);
+    } else if (_typeSystem.isSubtypeOf(
+        spreadType, _typeProvider.iterableDynamicType)) {
+      assert(_currentLiteralElementType != null);
+      final expectedType = _typeSystem.instantiateType(
+          _typeProvider.iterableType, [_currentLiteralElementType.type]);
+      final expectedDecoratedType = DecoratedType.forImplicitType(
+          _typeProvider, expectedType, _graph,
+          typeArguments: [_currentLiteralElementType]);
+
+      _handleAssignment(node.expression,
+          destinationType: expectedDecoratedType);
+    } else {
+      // Downcast. We can't assume nullability here, so do nothing.
+    }
+
+    if (!node.isNullAware) {
+      _checkExpressionNotNull(node.expression);
+    }
+
+    return null;
+  }
+
+  @override
   DecoratedType visitStringLiteral(StringLiteral node) {
     node.visitChildren(this);
     return DecoratedType(node.staticType, _graph.never);
@@ -1076,6 +1188,26 @@
   }
 
   @override
+  DecoratedType visitSwitchStatement(SwitchStatement node) {
+    node.expression.accept(this);
+    _flowAnalysis.switchStatement_expressionEnd(node);
+    var notPromoted = _assignedVariables.writtenInNode(node);
+    var hasDefault = false;
+    for (var member in node.members) {
+      var hasLabel = member.labels.isNotEmpty;
+      _flowAnalysis.switchStatement_beginCase(hasLabel, notPromoted);
+      if (member is SwitchCase) {
+        member.expression.accept(this);
+      } else {
+        hasDefault = true;
+      }
+      member.statements.accept(this);
+    }
+    _flowAnalysis.switchStatement_end(hasDefault);
+    return null;
+  }
+
+  @override
   DecoratedType visitSymbolLiteral(SymbolLiteral node) {
     return DecoratedType(node.staticType, _graph.never);
   }
@@ -1089,6 +1221,7 @@
   DecoratedType visitThrowExpression(ThrowExpression node) {
     node.expression.accept(this);
     // TODO(paulberry): do we need to check the expression type?  I think not.
+    _flowAnalysis.handleExit();
     return DecoratedType(node.staticType, _graph.never);
   }
 
@@ -1108,6 +1241,33 @@
   }
 
   @override
+  DecoratedType visitTryStatement(TryStatement node) {
+    var finallyBlock = node.finallyBlock;
+    if (finallyBlock != null) {
+      _flowAnalysis.tryFinallyStatement_bodyBegin();
+    }
+    var catchClauses = node.catchClauses;
+    if (catchClauses.isNotEmpty) {
+      _flowAnalysis.tryCatchStatement_bodyBegin();
+    }
+    var body = node.body;
+    body.accept(this);
+    var assignedInBody = _assignedVariables.writtenInNode(body);
+    if (catchClauses.isNotEmpty) {
+      _flowAnalysis.tryCatchStatement_bodyEnd(assignedInBody);
+      catchClauses.accept(this);
+      _flowAnalysis.tryCatchStatement_end();
+    }
+    if (finallyBlock != null) {
+      _flowAnalysis.tryFinallyStatement_finallyBegin(assignedInBody);
+      finallyBlock.accept(this);
+      _flowAnalysis.tryFinallyStatement_end(
+          _assignedVariables.writtenInNode(finallyBlock));
+    }
+    return null;
+  }
+
+  @override
   DecoratedType visitTypeName(TypeName typeName) {
     var typeArguments = typeName.typeArguments?.arguments;
     var element = typeName.name.staticElement;
@@ -1189,7 +1349,8 @@
   DecoratedType visitWhileStatement(WhileStatement node) {
     // Note: we do not create guards. A null check here is *very* unlikely to be
     // unnecessary after analysis.
-    _flowAnalysis.whileStatement_conditionBegin(_assignedVariables[node]);
+    _flowAnalysis
+        .whileStatement_conditionBegin(_assignedVariables.writtenInNode(node));
     _checkExpressionNotNull(node.condition);
     _flowAnalysis.whileStatement_bodyBegin(node, node.condition);
     _postDominatedLocals.doScoped(action: () => node.body.accept(this));
@@ -1214,19 +1375,25 @@
     // type of the expression, since all we are doing is causing a single graph
     // edge to be built; it is sufficient to pass in any decorated type whose
     // node is `never`.
+    if (_isPrefix(expression)) {
+      throw ArgumentError('cannot check non-nullability of a prefix');
+    }
     return _handleAssignment(expression, destinationType: _notNullType);
   }
 
-  /// Double checks that [name] is not the name of a method or getter declared
-  /// on [Object].
-  ///
-  /// TODO(paulberry): get rid of this method and put the correct logic into the
-  /// call sites.
-  void _checkNonObjectMember(String name) {
-    assert(name != 'toString');
-    assert(name != 'hashCode');
-    assert(name != 'noSuchMethod');
-    assert(name != 'runtimeType');
+  List<String> _computeObjectGetNames() {
+    var result = <String>[];
+    var objectClass = _typeProvider.objectType.element;
+    for (var accessor in objectClass.accessors) {
+      assert(accessor.isGetter);
+      assert(!accessor.name.startsWith('_'));
+      result.add(accessor.name);
+    }
+    for (var method in objectClass.methods) {
+      assert(!method.name.startsWith('_'));
+      result.add(method.name);
+    }
+    return result;
   }
 
   @override
@@ -1367,6 +1534,7 @@
   DecoratedType _handleAssignment(Expression expression,
       {DecoratedType destinationType,
       Expression destinationExpression,
+      _CompoundOperatorInfo compoundOperatorInfo,
       bool canInsertChecks = true}) {
     assert(
         (destinationExpression == null) != (destinationType == null),
@@ -1392,14 +1560,45 @@
           '(${expression.toSource()}) offset=${expression.offset}');
     }
     ExpressionChecks expressionChecks;
-    if (canInsertChecks) {
+    if (canInsertChecks && !sourceType.type.isDynamic) {
       expressionChecks = ExpressionChecks(expression.end);
       _variables.recordExpressionChecks(source, expression, expressionChecks);
     }
-    _checkAssignment(expressionChecks,
-        source: sourceType,
-        destination: destinationType,
-        hard: _postDominatedLocals.isReferenceInScope(expression));
+    if (compoundOperatorInfo != null) {
+      var compoundOperatorMethod = compoundOperatorInfo.method;
+      if (compoundOperatorMethod != null) {
+        _checkAssignment(
+            CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+            source: destinationType,
+            destination: _notNullType,
+            hard:
+                _postDominatedLocals.isReferenceInScope(destinationExpression));
+        DecoratedType compoundOperatorType =
+            getOrComputeElementType(compoundOperatorMethod);
+        assert(compoundOperatorType.positionalParameters.length > 0);
+        _checkAssignment(expressionChecks,
+            source: sourceType,
+            destination: compoundOperatorType.positionalParameters[0],
+            hard: _postDominatedLocals.isReferenceInScope(expression));
+        sourceType = _fixNumericTypes(compoundOperatorType.returnType,
+            compoundOperatorInfo.undecoratedType);
+        _checkAssignment(
+            CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+            source: sourceType,
+            destination: destinationType,
+            hard: false);
+      } else {
+        sourceType = _dynamicType;
+      }
+    } else {
+      _checkAssignment(expressionChecks,
+          source: sourceType,
+          destination: destinationType,
+          hard: _postDominatedLocals.isReferenceInScope(expression));
+    }
+    if (destinationExpression != null) {
+      _postDominatedLocals.removeReferenceFromAllScopes(destinationExpression);
+    }
     if (destinationLocalVariable != null) {
       _flowAnalysis.write(destinationLocalVariable);
     }
@@ -1408,8 +1607,9 @@
 
   DecoratedType _handleCollectionElement(CollectionElement element) {
     if (element is Expression) {
-      assert(_currentLiteralType != null);
-      return _handleAssignment(element, destinationType: _currentLiteralType);
+      assert(_currentLiteralElementType != null);
+      return _handleAssignment(element,
+          destinationType: _currentLiteralElementType);
     } else {
       return element.accept(this);
     }
@@ -1423,10 +1623,14 @@
     }
     var redirectedClass = callee.enclosingElement;
     var calleeType = _variables.decoratedElementType(callee);
+    var typeArguments = redirectedConstructor.type.typeArguments;
+    var typeArgumentTypes =
+        typeArguments?.arguments?.map((t) => t.type)?.toList();
     _handleInvocationArguments(
         redirectedConstructor,
         parameters.parameters,
-        redirectedConstructor.type.typeArguments,
+        typeArguments,
+        typeArgumentTypes,
         calleeType,
         redirectedClass.typeParameters);
   }
@@ -1539,31 +1743,37 @@
     }
   }
 
-  void _handleForLoopParts(AstNode node, ForLoopParts parts, AstNode body) {
+  void _handleForLoopParts(AstNode node, ForLoopParts parts, AstNode body,
+      DecoratedType Function(AstNode) bodyHandler) {
     if (parts is ForParts) {
       if (parts is ForPartsWithDeclarations) {
         parts.variables?.accept(this);
       } else if (parts is ForPartsWithExpression) {
         parts.initialization?.accept(this);
       }
+      _flowAnalysis.for_conditionBegin(_assignedVariables.writtenInNode(node));
       if (parts.condition != null) {
         _checkExpressionNotNull(parts.condition);
       }
+      _flowAnalysis.for_bodyBegin(
+          node is Statement ? node : null, parts.condition);
     } else if (parts is ForEachParts) {
       if (parts is ForEachPartsWithDeclaration) {
         _flowAnalysis.add(parts.loopVariable.declaredElement, assigned: true);
       }
       _checkExpressionNotNull(parts.iterable);
-      _flowAnalysis.forEach_bodyBegin(_assignedVariables[node]);
+      _flowAnalysis.forEach_bodyBegin(_assignedVariables.writtenInNode(node));
     }
 
     // The condition may fail/iterable may be empty, so the body gets a new
     // post-dominator scope.
     _postDominatedLocals.doScoped(action: () {
-      body.accept(this);
+      bodyHandler(body);
 
       if (parts is ForParts) {
+        _flowAnalysis.for_updaterBegin();
         parts.updaters.accept(this);
+        _flowAnalysis.for_end();
       } else {
         _flowAnalysis.forEach_end();
       }
@@ -1579,8 +1789,10 @@
       AstNode node,
       Iterable<AstNode> arguments,
       TypeArgumentList typeArguments,
+      List<DartType> typeArgumentTypes,
       DecoratedType calleeType,
-      List<TypeParameterElement> constructorTypeParameters) {
+      List<TypeParameterElement> constructorTypeParameters,
+      {DartType invokeType}) {
     var typeFormals = constructorTypeParameters ?? calleeType.typeFormals;
     if (typeFormals.isNotEmpty) {
       if (typeArguments != null) {
@@ -1595,7 +1807,21 @@
           calleeType = calleeType.instantiate(argumentTypes);
         }
       } else {
-        _unimplemented(node, 'Inferred type parameters in invocation');
+        if (invokeType is FunctionType) {
+          var argumentTypes = typeArgumentTypes
+              .map((argType) =>
+                  DecoratedType.forImplicitType(_typeProvider, argType, _graph))
+              .toList();
+          calleeType = calleeType.instantiate(argumentTypes);
+        } else if (constructorTypeParameters != null) {
+          // No need to instantiate; caller has already substituted in the
+          // correct type arguments.
+        } else {
+          assert(
+              false,
+              'invoke type should be a non-null function type, or '
+              'dynamic/Function, which have no type arguments.');
+        }
       }
     }
     int i = 0;
@@ -1644,16 +1870,20 @@
       Expression node, Expression target, SimpleIdentifier propertyName) {
     DecoratedType targetType;
     bool isConditional = _isConditionalExpression(node);
-    if (isConditional) {
+    var callee = propertyName.staticElement;
+    bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
+    if (_isPrefix(target)) {
+      return propertyName.accept(this);
+    } else if (calleeIsStatic) {
+      target.accept(this);
+    } else if (isConditional) {
       targetType = target.accept(this);
     } else {
-      _checkNonObjectMember(propertyName.name); // TODO(paulberry)
-      targetType = _checkExpressionNotNull(target);
+      targetType = _handleTarget(target, propertyName.name);
     }
-    var callee = propertyName.staticElement;
     if (callee == null) {
-      // TODO(paulberry)
-      _unimplemented(node, 'Unresolved property access');
+      // Dynamic dispatch.
+      return _dynamicType;
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     // TODO(paulberry): substitute if necessary
@@ -1675,6 +1905,14 @@
     }
   }
 
+  DecoratedType _handleTarget(Expression target, String name) {
+    if ((_objectGetNames ??= _computeObjectGetNames()).contains(name)) {
+      return target.accept(this);
+    } else {
+      return _checkExpressionNotNull(target);
+    }
+  }
+
   bool _isConditionalExpression(Expression expression) {
     Token token;
     if (expression is MethodInvocation) {
@@ -1698,6 +1936,9 @@
     }
   }
 
+  bool _isPrefix(Expression e) =>
+      e is SimpleIdentifier && e.staticElement is PrefixElement;
+
   bool _isUntypedParameter(NormalFormalParameter parameter) {
     if (parameter is SimpleFormalParameter) {
       return parameter.type == null;
@@ -1773,6 +2014,8 @@
 
   NullabilityGraph get _graph;
 
+  TypeProvider get _typeProvider;
+
   TypeSystem get _typeSystem;
 
   /// Creates the necessary constraint(s) for an assignment from [source] to
@@ -1783,8 +2026,43 @@
       @required DecoratedType destination,
       @required bool hard}) {
     _connect(source.node, destination.node, origin, hard: hard);
+    _checkAssignment_recursion(origin,
+        source: source, destination: destination);
+  }
+
+  /// Does the recursive part of [_checkAssignment], visiting all of the types
+  /// constituting [source] and [destination], and creating the appropriate
+  /// edges between them.
+  void _checkAssignment_recursion(EdgeOrigin origin,
+      {@required DecoratedType source, @required DecoratedType destination}) {
     var sourceType = source.type;
     var destinationType = destination.type;
+    if (destinationType.isDartAsyncFutureOr) {
+      // (From the subtyping spec):
+      // if T1 is FutureOr<S1> then T0 <: T1 iff any of the following hold:
+      // - either T0 <: Future<S1>
+      var s1 = destination.typeArguments[0];
+      if (_typeSystem.isSubtypeOf(
+          sourceType, _typeProvider.futureType.instantiate([s1.type]))) {
+        // E.g. FutureOr<int> = (... as Future<int>)
+        // This is handled by the InterfaceType logic below, since we treat
+        // FutureOr as a supertype of Future.
+      }
+      // - or T0 <: S1
+      else if (_typeSystem.isSubtypeOf(sourceType, s1.type)) {
+        // E.g. FutureOr<int> = (... as int)
+        _checkAssignment_recursion(origin, source: source, destination: s1);
+        return;
+      }
+      // - or T0 is X0 and X0 has bound S0 and S0 <: T1
+      // - or T0 is X0 & S0 and S0 <: T1
+      else if (sourceType is TypeParameterType) {
+        throw UnimplementedError('TODO(paulberry)');
+      } else {
+        // Not a subtype; this must be a downcast.
+        throw UnimplementedError('TODO(paulberry)');
+      }
+    }
     if (sourceType.isBottom || sourceType.isDartCoreNull) {
       // No further edges need to be created, since all types are trivially
       // supertypes of bottom (and of Null, in the pre-migration world).
@@ -1872,6 +2150,9 @@
       }
     } else if (destinationType.isDynamic || sourceType.isDynamic) {
       // ok; nothing further to do.
+    } else if (destinationType is InterfaceType && sourceType is FunctionType) {
+      // Either this is an upcast to Function or Object, or it is erroneous
+      // code.  In either case we don't need to create any additional edges.
     } else {
       throw '$destination <= $source'; // TODO(paulberry)
     }
@@ -1885,6 +2166,14 @@
   DecoratedType _getTypeParameterTypeBound(DecoratedType type);
 }
 
+class _CompoundOperatorInfo {
+  final MethodElement method;
+  final int offset;
+  final DartType undecoratedType;
+
+  _CompoundOperatorInfo(this.method, this.offset, this.undecoratedType);
+}
+
 /// Information about a binary expression whose boolean value could possibly
 /// affect nullability analysis.
 class _ConditionInfo {
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 9c52df8..efc646b 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -16,6 +16,12 @@
   AlwaysNullableTypeOrigin(Source source, int offset) : super(source, offset);
 }
 
+/// Edge origin resulting from the use of a value on the LHS of a compound
+/// assignment.
+class CompoundAssignmentOrigin extends EdgeOriginWithLocation {
+  CompoundAssignmentOrigin(Source source, int offset) : super(source, offset);
+}
+
 /// Common interface for classes providing information about how an edge came
 /// to be; that is, what was found in the source code that led the migration
 /// tool to create the edge.
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 9ab1383..01061d1 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -60,22 +60,37 @@
 
   final TypeProvider _typeProvider;
 
+  /// For convenience, a [DecoratedType] representing `dynamic`.
+  final DecoratedType _dynamicType;
+
   /// For convenience, a [DecoratedType] representing non-nullable `Object`.
   final DecoratedType _nonNullableObjectType;
 
+  /// For convenience, a [DecoratedType] representing non-nullable `StackTrace`.
+  final DecoratedType _nonNullableStackTraceType;
+
   NodeBuilder(this._variables, this.source, this.listener, this._graph,
       this._typeProvider)
-      : _nonNullableObjectType =
-            DecoratedType(_typeProvider.objectType, _graph.never);
+      : _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always),
+        _nonNullableObjectType =
+            DecoratedType(_typeProvider.objectType, _graph.never),
+        _nonNullableStackTraceType =
+            DecoratedType(_typeProvider.stackTraceType, _graph.never);
 
   @override
   DecoratedType visitCatchClause(CatchClause node) {
     DecoratedType exceptionType = node.exceptionType?.accept(this);
     if (node.exceptionParameter != null) {
-      exceptionType ??= DecoratedType(_typeProvider.objectType, _graph.never);
+      // If there is no `on Type` part of the catch clause, the type is dynamic.
+      exceptionType ??= _dynamicType;
       _variables.recordDecoratedElementType(
           node.exceptionParameter.staticElement, exceptionType);
     }
+    if (node.stackTraceParameter != null) {
+      // The type of stack traces is always StackTrace (non-nullable).
+      _variables.recordDecoratedElementType(
+          node.stackTraceParameter.staticElement, _nonNullableStackTraceType);
+    }
     node.stackTraceParameter?.accept(this);
     node.body?.accept(this);
     return null;
@@ -366,18 +381,26 @@
         parent is ImplementsClause ||
         parent is WithClause ||
         parent is OnClause ||
-        parent is ClassTypeAlias ||
-        parent is CatchClause) {
+        parent is ClassTypeAlias) {
       nullabilityNode = _graph.never;
     } else {
       nullabilityNode = NullabilityNode.forTypeAnnotation(node.end);
     }
-    var decoratedType = DecoratedType(type, nullabilityNode,
-        typeArguments: typeArguments,
-        returnType: decoratedReturnType,
-        positionalParameters: positionalParameters,
-        namedParameters: namedParameters,
-        typeFormalBounds: typeFormalBounds);
+    DecoratedType decoratedType;
+    if (type is FunctionType && node is! GenericFunctionType) {
+      // node is a reference to a typedef.  Treat it like an inferred type (we
+      // synthesize new nodes for it).  These nodes will be unioned with the
+      // typedef nodes by the edge builder.
+      decoratedType = DecoratedType.forImplicitFunction(
+          _typeProvider, type, nullabilityNode, _graph);
+    } else {
+      decoratedType = DecoratedType(type, nullabilityNode,
+          typeArguments: typeArguments,
+          returnType: decoratedReturnType,
+          positionalParameters: positionalParameters,
+          namedParameters: namedParameters,
+          typeFormalBounds: typeFormalBounds);
+    }
     _variables.recordDecoratedTypeAnnotation(
         source,
         node,
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index d6baf2e..53c75ec 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -18,7 +18,7 @@
 class NullabilityMigrationImpl implements NullabilityMigration {
   final NullabilityMigrationListener listener;
 
-  final Variables _variables;
+  Variables _variables;
 
   final NullabilityGraph _graph;
 
@@ -34,22 +34,26 @@
       {bool permissive: false})
       : this._(listener, NullabilityGraph(), permissive);
 
-  NullabilityMigrationImpl._(this.listener, this._graph, this._permissive)
-      : _variables = Variables(_graph);
+  NullabilityMigrationImpl._(this.listener, this._graph, this._permissive);
 
   void finish() {
     _graph.propagate();
     if (_graph.unsatisfiedSubstitutions.isNotEmpty) {
-      throw new UnimplementedError('Need to report unsatisfied substitutions');
+      // TODO(paulberry): for now we just ignore unsatisfied substitutions, to
+      // work around https://github.com/dart-lang/sdk/issues/38257
+      // throw new UnimplementedError('Need to report unsatisfied substitutions');
     }
     // TODO(paulberry): it would be nice to report on unsatisfied edges as well,
     // however, since every `!` we add has an unsatisfied edge associated with
     // it, we can't report on every unsatisfied edge.  We need to figure out a
     // way to report unsatisfied edges that isn't too overwhelming.
-    broadcast(_variables, listener);
+    if (_variables != null) {
+      broadcast(_variables, listener);
+    }
   }
 
   void prepareInput(ResolvedUnitResult result) {
+    _variables ??= Variables(_graph, result.typeProvider);
     var unit = result.unit;
     unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
         _permissive ? listener : null, _graph, result.typeProvider));
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index 96ef894..244df1e 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -81,6 +81,10 @@
   /// propagation.
   static const _debugBeforePropagation = false;
 
+  /// Set this const to `true` to dump the nullability graph just before
+  /// propagation.
+  static const _debugAfterPropagation = false;
+
   /// Set containing all [NullabilityNode]s that have been passed as the
   /// `sourceNode` argument to [connect].
   final _allSourceNodes = Set<NullabilityNode>.identity();
@@ -157,6 +161,7 @@
     _propagateAlways();
     _propagateUpstream();
     _propagateDownstream();
+    if (_debugAfterPropagation) _debugDump();
   }
 
   /// Records that nodes [x] and [y] should have exactly the same nullability.
@@ -344,20 +349,29 @@
 /// testing.
 @visibleForTesting
 class NullabilityGraphForTesting extends NullabilityGraph {
-  /// Iterates through all edges that have this node as one of their sources.
-  ///
-  /// There is no guarantee of uniqueness of the iterated edges.
-  @visibleForTesting
-  Iterable<NullabilityEdge> getDownstreamEdges(NullabilityNode node) {
-    return node._downstreamEdges;
+  final List<NullabilityEdge> _allEdges = [];
+
+  /// Prints out a representation of the graph nodes.  Useful in debugging
+  /// broken tests.
+  void debugDump() {
+    _debugDump();
   }
 
-  /// Iterates through all edges that have this node as their destination.
-  ///
-  /// There is no guarantee of uniqueness of the iterated nodes.
+  /// Iterates through all edges in the graph.
   @visibleForTesting
-  Iterable<NullabilityEdge> getUpstreamEdges(NullabilityNode node) {
-    return node._upstreamEdges;
+  Iterable<NullabilityEdge> getAllEdges() {
+    return _allEdges;
+  }
+
+  @override
+  NullabilityEdge _connect(
+      List<NullabilityNode> sources,
+      NullabilityNode destinationNode,
+      _NullabilityEdgeKind kind,
+      EdgeOrigin origin) {
+    var edge = super._connect(sources, destinationNode, kind, origin);
+    _allEdges.add(edge);
+    return edge;
   }
 }
 
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 21f5a7b..e1e88ee 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
 import 'package:nnbd_migration/src/conditional_discard.dart';
@@ -32,14 +33,15 @@
 
   final AlreadyMigratedCodeDecorator _alreadyMigratedCodeDecorator;
 
-  Variables(this._graph)
-      : _alreadyMigratedCodeDecorator = AlreadyMigratedCodeDecorator(_graph);
+  Variables(this._graph, TypeProvider typeProvider)
+      : _alreadyMigratedCodeDecorator =
+            AlreadyMigratedCodeDecorator(_graph, typeProvider);
 
   @override
   Map<ClassElement, DecoratedType> decoratedDirectSupertypes(
       ClassElement class_) {
     assert(class_ is! ClassElementHandle);
-    return _decoratedDirectSupertypes[class_] ??
+    return _decoratedDirectSupertypes[class_] ??=
         _decorateDirectSupertypes(class_);
   }
 
@@ -230,9 +232,9 @@
     }
 
     DecoratedType decoratedType;
-    if (element is ExecutableElement) {
+    if (element is FunctionTypedElement) {
       decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
-    } else if (element is TopLevelVariableElement) {
+    } else if (element is VariableElement) {
       decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
     } else {
       // TODO(paulberry)
@@ -246,9 +248,8 @@
   Map<ClassElement, DecoratedType> _decorateDirectSupertypes(
       ClassElement class_) {
     var result = <ClassElement, DecoratedType>{};
-    for (var supertype in class_.allSupertypes) {
-      var decoratedSupertype =
-          _alreadyMigratedCodeDecorator.decorate(supertype);
+    for (var decoratedSupertype
+        in _alreadyMigratedCodeDecorator.getImmediateSupertypes(class_)) {
       assert(identical(decoratedSupertype.node, _graph.never));
       var class_ = (decoratedSupertype.type as InterfaceType).element;
       if (class_ is ClassElementHandle) {
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index d257f73..b2b058c 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -2,10 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
@@ -29,40 +31,71 @@
   final NullabilityGraphForTesting graph;
 
   factory _AlreadyMigratedCodeDecoratorTest() {
-    return _AlreadyMigratedCodeDecoratorTest._(NullabilityGraphForTesting());
+    return _AlreadyMigratedCodeDecoratorTest._(
+        NullabilityGraphForTesting(), TestTypeProvider());
   }
 
-  _AlreadyMigratedCodeDecoratorTest._(this.graph)
-      : typeProvider = TestTypeProvider(),
-        decorator = AlreadyMigratedCodeDecorator(graph);
+  _AlreadyMigratedCodeDecoratorTest._(this.graph, this.typeProvider)
+      : decorator = AlreadyMigratedCodeDecorator(graph, typeProvider);
+
+  NullabilityNode get always => graph.always;
+
+  NullabilityNode get never => graph.never;
 
   void checkDynamic(DecoratedType decoratedType) {
     expect(decoratedType.type, same(typeProvider.dynamicType));
-    expect(decoratedType.node, same(graph.always));
+    expect(decoratedType.node, same(always));
   }
 
-  void checkInt(DecoratedType decoratedType) {
-    expect(decoratedType.type, typeProvider.intType);
-    expect(decoratedType.node, same(graph.never));
-  }
-
-  void checkIterable(
-      DecoratedType decoratedType, void Function(DecoratedType) checkArgument) {
-    expect(decoratedType.type, typeProvider.iterableDynamicType);
-    expect(decoratedType.node, same(graph.never));
+  void checkFutureOr(
+      DecoratedType decoratedType,
+      NullabilityNode expectedNullability,
+      void Function(DecoratedType) checkArgument) {
+    expect(decoratedType.type.element, typeProvider.futureOrType.element);
+    expect(decoratedType.node, expectedNullability);
     checkArgument(decoratedType.typeArguments[0]);
   }
 
+  void checkInt(
+      DecoratedType decoratedType, NullabilityNode expectedNullability) {
+    expect(decoratedType.type.element, typeProvider.intType.element);
+    expect(decoratedType.node, expectedNullability);
+  }
+
+  void checkIterable(
+      DecoratedType decoratedType,
+      NullabilityNode expectedNullability,
+      void Function(DecoratedType) checkArgument) {
+    expect(
+        decoratedType.type.element, typeProvider.iterableDynamicType.element);
+    expect(decoratedType.node, expectedNullability);
+    checkArgument(decoratedType.typeArguments[0]);
+  }
+
+  void checkNum(
+      DecoratedType decoratedType, NullabilityNode expectedNullability) {
+    expect(decoratedType.type.element, typeProvider.numType.element);
+    expect(decoratedType.node, expectedNullability);
+  }
+
+  void checkObject(
+      DecoratedType decoratedType, NullabilityNode expectedNullability) {
+    expect(decoratedType.type.element, typeProvider.objectType.element);
+    expect(decoratedType.node, expectedNullability);
+  }
+
   void checkTypeParameter(
-      DecoratedType decoratedType, TypeParameterElementImpl expectedElement) {
+      DecoratedType decoratedType,
+      NullabilityNode expectedNullability,
+      TypeParameterElement expectedElement) {
     var type = decoratedType.type as TypeParameterTypeImpl;
     expect(type.element, same(expectedElement));
-    expect(decoratedType.node, same(graph.never));
+    expect(decoratedType.node, expectedNullability);
   }
 
   void checkVoid(DecoratedType decoratedType) {
     expect(decoratedType.type, same(typeProvider.voidType));
-    expect(decoratedType.node, same(graph.always));
+    expect(decoratedType.node, same(always));
   }
 
   DecoratedType decorate(DartType type) {
@@ -75,6 +108,25 @@
     checkDynamic(decorate(typeProvider.dynamicType));
   }
 
+  test_decorate_functionType_generic_bounded() {
+    var typeFormal = TypeParameterElementImpl.synthetic('T')
+      ..bound = typeProvider.numType;
+    var decoratedType = decorate(FunctionTypeImpl.synthetic(
+        TypeParameterTypeImpl(typeFormal), [typeFormal], []));
+    expect(decoratedType.typeFormalBounds, hasLength(1));
+    checkNum(decoratedType.typeFormalBounds[0], never);
+    checkTypeParameter(decoratedType.returnType, never, typeFormal);
+  }
+
+  test_decorate_functionType_generic_no_explicit_bound() {
+    var typeFormal = TypeParameterElementImpl.synthetic('T');
+    var decoratedType = decorate(FunctionTypeImpl.synthetic(
+        TypeParameterTypeImpl(typeFormal), [typeFormal], []));
+    expect(decoratedType.typeFormalBounds, hasLength(1));
+    checkObject(decoratedType.typeFormalBounds[0], always);
+    checkTypeParameter(decoratedType.returnType, never, typeFormal);
+  }
+
   test_decorate_functionType_named_parameter() {
     checkDynamic(
         decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [
@@ -99,6 +151,14 @@
     ])).positionalParameters[0]);
   }
 
+  test_decorate_functionType_question() {
+    expect(
+        decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [],
+                nullabilitySuffix: NullabilitySuffix.question))
+            .node,
+        same(always));
+  }
+
   test_decorate_functionType_returnType() {
     checkDynamic(
         decorate(FunctionTypeImpl.synthetic(typeProvider.dynamicType, [], []))
@@ -110,17 +170,35 @@
         decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [],
                 nullabilitySuffix: NullabilitySuffix.star))
             .node,
-        same(graph.never));
+        same(never));
+  }
+
+  test_decorate_interfaceType_simple_question() {
+    checkInt(
+        decorate(InterfaceTypeImpl(typeProvider.intType.element,
+            nullabilitySuffix: NullabilitySuffix.question)),
+        always);
   }
 
   test_decorate_interfaceType_simple_star() {
-    checkInt(decorate(InterfaceTypeImpl(typeProvider.intType.element,
-        nullabilitySuffix: NullabilitySuffix.star)));
+    checkInt(
+        decorate(InterfaceTypeImpl(typeProvider.intType.element,
+            nullabilitySuffix: NullabilitySuffix.star)),
+        never);
   }
 
   test_decorate_iterable_dynamic() {
     var decorated = decorate(typeProvider.iterableDynamicType);
-    checkIterable(decorated, checkDynamic);
+    checkIterable(decorated, never, checkDynamic);
+  }
+
+  test_decorate_typeParameterType_question() {
+    var element = TypeParameterElementImpl.synthetic('T');
+    checkTypeParameter(
+        decorate(TypeParameterTypeImpl(element,
+            nullabilitySuffix: NullabilitySuffix.question)),
+        always,
+        element);
   }
 
   test_decorate_typeParameterType_star() {
@@ -128,10 +206,70 @@
     checkTypeParameter(
         decorate(TypeParameterTypeImpl(element,
             nullabilitySuffix: NullabilitySuffix.star)),
+        never,
         element);
   }
 
   test_decorate_void() {
     checkVoid(decorate(typeProvider.voidType));
   }
+
+  test_getImmediateSupertypes_future() {
+    var element = typeProvider.futureType.element;
+    var decoratedSupertypes =
+        decorator.getImmediateSupertypes(element).toList();
+    var typeParam = element.typeParameters[0];
+    expect(decoratedSupertypes, hasLength(2));
+    checkObject(decoratedSupertypes[0], never);
+    // Since Future<T> is a subtype of FutureOr<T>, we consider FutureOr<T> to
+    // be an immediate supertype, even though the class declaration for Future
+    // doesn't mention FutureOr.
+    checkFutureOr(decoratedSupertypes[1], never,
+        (t) => checkTypeParameter(t, never, typeParam));
+  }
+
+  test_getImmediateSupertypes_generic() {
+    var t = ElementFactory.typeParameterElement('T');
+    var class_ = ElementFactory.classElement3(
+        name: 'C',
+        typeParameters: [t],
+        supertype: typeProvider.iterableType.instantiate([t.type]));
+    var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+    expect(decoratedSupertypes, hasLength(1));
+    checkIterable(decoratedSupertypes[0], never,
+        (type) => checkTypeParameter(type, never, t));
+  }
+
+  test_getImmediateSupertypes_interface() {
+    var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+    class_.interfaces = [typeProvider.numType];
+    var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+    expect(decoratedSupertypes, hasLength(2));
+    checkObject(decoratedSupertypes[0], never);
+    checkNum(decoratedSupertypes[1], never);
+  }
+
+  test_getImmediateSupertypes_mixin() {
+    var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+    class_.mixins = [typeProvider.numType];
+    var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+    expect(decoratedSupertypes, hasLength(2));
+    checkObject(decoratedSupertypes[0], never);
+    checkNum(decoratedSupertypes[1], never);
+  }
+
+  test_getImmediateSupertypes_superclassConstraint() {
+    var class_ = ElementFactory.mixinElement(
+        name: 'C', constraints: [typeProvider.numType]);
+    var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+    expect(decoratedSupertypes, hasLength(1));
+    checkNum(decoratedSupertypes[0], never);
+  }
+
+  test_getImmediateSupertypes_supertype() {
+    var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+    var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+    expect(decoratedSupertypes, hasLength(1));
+    checkObject(decoratedSupertypes[0], never);
+  }
 }
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index c00be10..e7593d2 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -91,6 +91,86 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_catch_simple() async {
+    var content = '''
+void f() {
+  try {} catch (ex, st) {}
+}
+''';
+    var expected = '''
+void f() {
+  try {} catch (ex, st) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_catch_simple_with_modifications() async {
+    var content = '''
+void f(String x, StackTrace y) {
+  try {} catch (ex, st) {
+    ex = x;
+    st = y;
+  }
+}
+main() {
+  f(null, null);
+}
+''';
+    var expected = '''
+void f(String? x, StackTrace? y) {
+  try {} catch (ex, st) {
+    ex = x;
+    st = y!;
+  }
+}
+main() {
+  f(null, null);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_catch_with_on() async {
+    var content = '''
+void f() {
+  try {} on String catch (ex, st) {}
+}
+''';
+    var expected = '''
+void f() {
+  try {} on String catch (ex, st) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_catch_with_on_with_modifications() async {
+    var content = '''
+void f(String x, StackTrace y) {
+  try {} on String catch (ex, st) {
+    ex = x;
+    st = y;
+  }
+}
+main() {
+  f(null, null);
+}
+''';
+    var expected = '''
+void f(String? x, StackTrace? y) {
+  try {} on String? catch (ex, st) {
+    ex = x;
+    st = y!;
+  }
+}
+main() {
+  f(null, null);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_class_alias_synthetic_constructor_with_parameters() async {
     var content = '''
 void main() {
@@ -821,6 +901,72 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_dynamic_method_call() async {
+    var content = '''
+class C {
+  int g(int i) => i;
+}
+int f(bool b, dynamic d) {
+  if (b) return 0;
+  return d.g(null);
+}
+main() {
+  f(true, null);
+  f(false, C());
+}
+''';
+    // `d.g(null)` is a dynamic call, so we can't tell that it will target `C.g`
+    // at runtime.  So we can't figure out that we need to make g's argument and
+    // return types nullable.
+    //
+    // We do, however, make f's return type nullable, since there is no way of
+    // knowing whether a dynamic call will return `null`.
+    var expected = '''
+class C {
+  int g(int i) => i;
+}
+int? f(bool b, dynamic d) {
+  if (b) return 0;
+  return d.g(null);
+}
+main() {
+  f(true, null);
+  f(false, C());
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_dynamic_property_access() async {
+    var content = '''
+class C {
+  int get g => 0;
+}
+int f(bool b, dynamic d) {
+  if (b) return 0;
+  return d.g;
+}
+main() {
+  f(true, null);
+  f(false, C());
+}
+''';
+    var expected = '''
+class C {
+  int get g => 0;
+}
+int? f(bool b, dynamic d) {
+  if (b) return 0;
+  return d.g;
+}
+main() {
+  f(true, null);
+  f(false, C());
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_field_formal_param_typed() async {
     var content = '''
 class C {
@@ -935,6 +1081,54 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_field_initializer_untyped_list_literal() async {
+    var content = '''
+class C {
+  List<int> f;
+  C() : f = [null];
+}
+''';
+    var expected = '''
+class C {
+  List<int?> f;
+  C() : f = [null];
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_initializer_untyped_map_literal() async {
+    var content = '''
+class C {
+  Map<String, int> f;
+  C() : f = {"foo": null};
+}
+''';
+    var expected = '''
+class C {
+  Map<String, int?> f;
+  C() : f = {"foo": null};
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_initializer_untyped_set_literal() async {
+    var content = '''
+class C {
+  Set<int> f;
+  C() : f = {null};
+}
+''';
+    var expected = '''
+class C {
+  Set<int?> f;
+  C() : f = {null};
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_field_type_inferred() async {
     var content = '''
 int f() => null;
@@ -960,6 +1154,36 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_flow_analysis_complex() async {
+    var content = '''
+int f(int x) {
+  while (x == null) {
+    x = g(x);
+  }
+  return x;
+}
+int g(int x) => x == null ? 1 : null;
+main() {
+  f(null);
+}
+''';
+    // Flow analysis can tell that the loop only exits if x is non-null, so the
+    // return type of `f` can remain `int`, and no null check is needed.
+    var expected = '''
+int f(int? x) {
+  while (x == null) {
+    x = g(x);
+  }
+  return x;
+}
+int? g(int? x) => x == null ? 1 : null;
+main() {
+  f(null);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_flow_analysis_simple() async {
     var content = '''
 int f(int x) {
@@ -1448,6 +1672,77 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @failingTest
+  test_map_nullable_input() async {
+    // TODO(paulberry): we're currently migrating this example incorrectly.
+    // See discussion at https://dart-review.googlesource.com/c/sdk/+/115766
+    var content = '''
+Iterable<int> f(List<int> x) => x.map((y) => g(y));
+int g(int x) => x + 1;
+main() {
+  f([null]);
+}
+''';
+    var expected = '''
+Iterable<int> f(List<int?> x) => x.map((y) => g(y!));
+int g(int x) => x + 1;
+main() {
+  f([null]);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_map_nullable_output() async {
+    var content = '''
+Iterable<int> f(List<int> x) => x.map((y) => g(y));
+int g(int x) => null;
+main() {
+  f([1]);
+}
+''';
+    var expected = '''
+Iterable<int?> f(List<int> x) => x.map((y) => g(y));
+int? g(int x) => null;
+main() {
+  f([1]);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_methodInvocation_typeArguments_explicit() async {
+    var content = '''
+T f<T>(T t) => t;
+void g() {
+  int x = f<int>(null);
+}
+''';
+    var expected = '''
+T f<T>(T t) => t;
+void g() {
+  int? x = f<int?>(null);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_methodInvocation_typeArguments_inferred() async {
+    var content = '''
+T f<T>(T t) => t;
+void g() {
+  int x = f(null);
+}
+''';
+    var expected = '''
+T f<T>(T t) => t;
+void g() {
+  int? x = f(null);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_multiDeclaration_innerUsage() async {
     var content = '''
 void test() {
@@ -2036,6 +2331,36 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_prefixes() async {
+    var root = '/home/test/lib';
+    var path1 = convertPath('$root/file1.dart');
+    var file1 = '''
+import 'file2.dart';
+int x;
+int f() => null;
+''';
+    var expected1 = '''
+import 'file2.dart';
+int? x;
+int? f() => null;
+''';
+    var path2 = convertPath('$root/file2.dart');
+    var file2 = '''
+import 'file1.dart' as f1;
+void main() {
+  f1.x = f1.f();
+}
+''';
+    var expected2 = '''
+import 'file1.dart' as f1;
+void main() {
+  f1.x = f1.f();
+}
+''';
+    await _checkMultipleFileChanges(
+        {path1: file1, path2: file2}, {path1: expected1, path2: expected2});
+  }
+
   test_prefixExpression_bang() async {
     var content = '''
 bool f(bool b) => !b;
diff --git a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
index 07b8aeb..3643d8a 100644
--- a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
@@ -230,6 +230,78 @@
     assertEdge(iNode, jNode, hard: false);
   }
 
+  test_catch_cancels_promotions_based_on_assignments_in_body() async {
+    await analyze('''
+void f(int i) {
+  if (i == null) return;
+  try {
+    g(i);
+    i = null;
+    if (i == null) return;
+    g(i);
+  } catch (_) {
+    h(i);
+  }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to j because i is promoted at the time of both calls to g.
+    assertNoEdge(iNode, jNode);
+    // But there is an edge from i to k, because there is no guarantee that i is
+    // promoted at all times during the execution of the try block.
+    assertEdge(iNode, kNode, hard: false);
+  }
+
+  test_catch_falls_through_to_after_try() async {
+    await analyze('''
+void f(int i) {
+  try {
+    g(i);
+    return;
+  } catch (_) {
+    if (i == null) return;
+  }
+  h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i's type is promoted to non-nullable
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j.
+    assertEdge(iNode, jNode, hard: true);
+  }
+
+  test_catch_resets_to_state_before_try() async {
+    await analyze('''
+void f(int i) {
+  try {
+    if (i == null) return;
+    g(i);
+  } catch (_) {
+    h(i);
+  }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to j because i's type is promoted to non-nullable
+    assertNoEdge(iNode, jNode);
+    // But there is an edge from i to k, since we assume an exception might
+    // occur at any time during the body of the try.
+    assertEdge(iNode, kNode, hard: false);
+  }
+
   test_conditionalExpression() async {
     await analyze('''
 int f(int i) => i == null ? g(i) : h(i);
@@ -455,6 +527,191 @@
     // field doesn't cause flow analysis to crash.
   }
 
+  test_finally_promotions_are_preserved() async {
+    await analyze('''
+void f(int i) {
+  try {
+    g(i);
+  } finally {
+    if (i == null) return;
+  }
+  h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i's type is promoted to non-nullable in the
+    // finally block.
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j.
+    assertEdge(iNode, jNode, hard: true);
+  }
+
+  test_finally_temporarily_resets_to_state_before_try() async {
+    await analyze('''
+void f(int i) {
+  try {
+    if (i == null) return;
+    g(i);
+  } finally {
+    h(i);
+  }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to j because i's type is promoted to non-nullable in the
+    // try-block.
+    assertNoEdge(iNode, jNode);
+    // But there is an edge from i to k, since we assume an exception might
+    // occur at any time during the body of the try.
+    assertEdge(iNode, kNode, hard: false);
+  }
+
+  test_for_break_target() async {
+    await analyze('''
+void f(int i) {
+  L: for (;;) {
+    for (;;) {
+      if (i != null) break L;
+      if (b()) break;
+    }
+    g(i);
+  }
+  h(i);
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i is promoted at the time of the call to h.
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j, because i is not promoted at the time
+    // of the call to g.
+    assertEdge(iNode, jNode, hard: false);
+  }
+
+  test_for_cancels_promotions_for_assignments_in_body() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  if (j == null) return;
+  for (;;) {
+    i.isEven;
+    j.isEven;
+    j = null;
+  }
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because is is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never because its promotion was cancelled.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_for_cancels_promotions_for_assignments_in_updaters() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  if (j == null) return;
+  for (;; j = null) {
+    i.isEven;
+    j.isEven;
+  }
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because is is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never because its promotion was cancelled.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_for_collection_cancels_promotions_for_assignments_in_body() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  if (j == null) return;
+  <Object>[for (;;) <Object>[i.isEven, j.isEven, (j = null)]];
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because is is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never because its promotion was cancelled.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_for_collection_cancels_promotions_for_assignments_in_updaters() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  if (j == null) return;
+  <Object>[for (;; j = null) <Object>[i.isEven, j.isEven]];
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because is is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never because its promotion was cancelled.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_for_collection_preserves_promotions_for_assignments_in_initializer() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  <Object>[for(var v = h(i.isEven && j.isEven && g(i = null));;) null];
+}
+bool g(int k) => true;
+int h(bool b) => 0;
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because it is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_for_continue_target() async {
+    await analyze('''
+void f(int i) {
+  L: for (; b(); h(i)) {
+    for (; b(); g(i)) {
+      if (i != null) continue L;
+    }
+    return;
+  }
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i is promoted at the time of the call to h.
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j, because i is not promoted at the time
+    // of the call to g.
+    assertEdge(iNode, jNode, hard: false);
+  }
+
   test_for_each_cancels_promotions_for_assignments_in_body() async {
     await analyze('''
 void f(int i, int j, Iterable<Object> x) {
@@ -525,6 +782,23 @@
     assertEdge(jNode, never, hard: false);
   }
 
+  test_for_preserves_promotions_for_assignments_in_initializer() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) return;
+  for(var v = h(i.isEven && j.isEven && g(i = null));;) {}
+}
+bool g(int k) => true;
+int h(bool b) => 0;
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to never because it is promoted.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never.
+    assertEdge(jNode, never, hard: false);
+  }
+
   test_functionDeclaration() async {
     await analyze('''
 void f(int i, int j) {
@@ -632,6 +906,25 @@
     assertEdge(iNode, jNode, hard: false, guards: [iNode]);
   }
 
+  test_ifNull() async {
+    await analyze('''
+void f(int i, int x) {
+  x ?? (i == null ? throw 'foo' : g(i));
+  h(i);
+}
+int g(int j) => 0;
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to j because i's type is promoted to non-nullable
+    assertNoEdge(iNode, jNode);
+    // But there is an edge from i to k, because the RHS of the `??` isn't
+    // guaranteed to execute.
+    assertEdge(iNode, kNode, hard: true);
+  }
+
   test_local_function_parameters() async {
     await analyze('''
 void f() {
@@ -650,6 +943,49 @@
     assertEdge(jNode, never, hard: false);
   }
 
+  test_not() async {
+    await analyze('''
+void f(int i) {
+  if (!(i == null)) {
+    h(i);
+  } else {
+    g(i);
+  }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i is known to be non-nullable at the site of
+    // the call to h()
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j
+    assertEdge(iNode, jNode, hard: false);
+  }
+
+  test_rethrow() async {
+    await analyze('''
+void f(int i, int j) {
+  try {
+    g();
+  } catch (_) {
+    if (i == null) rethrow;
+    print(i.isEven);
+    print(j.isEven);
+  }
+}
+void g() {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to `never` because i's type is promoted to non-nullable
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to `never`.
+    assertEdge(jNode, never, hard: false);
+  }
+
   test_return() async {
     await analyze('''
 void f(int i, int j) {
@@ -666,6 +1002,108 @@
     assertEdge(jNode, never, hard: false);
   }
 
+  test_switch_break_target() async {
+    await analyze('''
+void f(int i, int x, int y) {
+  L: switch (x) {
+    default:
+      switch (y) {
+        default:
+          if (i != null) break L;
+          if (b()) break;
+          return;
+      }
+      g(i);
+      return;
+  }
+  h(i);
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i is promoted at the time of the call to h.
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j, because i is not promoted at the time
+    // of the call to g.
+    assertEdge(iNode, jNode, hard: false);
+  }
+
+  test_switch_cancels_promotions_for_labeled_cases() async {
+    await analyze('''
+void f(int i, int x, bool b) {
+  if (i == null) return;
+  switch (x) {
+    L:
+    case 1:
+      g(i);
+      break;
+    case 2:
+      h(i);
+      i = null;
+      if (b) continue L;
+      break;
+  }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i's type is promoted to non-nullable at the
+    // time of the call to h.
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j.
+    assertEdge(iNode, jNode, hard: false);
+  }
+
+  test_switch_default() async {
+    await analyze('''
+void f(int i, int j, int x, int y) {
+  if (i == null) {
+    switch (x) {
+      default: return;
+    }
+  }
+  if (j == null) {
+    switch (y) {
+      case 0: return;
+    }
+  }
+  i.isEven;
+  j.isEven;
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to `never` because the switch statement is guaranteed to
+    // complete by returning, so i is promoted to non-nullable.
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to never, because the switch statement is not
+    // guaranteed to complete by returning, so j is not promoted.
+    assertEdge(jNode, never, hard: false);
+  }
+
+  test_throw() async {
+    await analyze('''
+void f(int i, int j) {
+  if (i == null) throw 'foo';
+  print(i.isEven);
+  print(j.isEven);
+}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    // No edge from i to `never` because i's type is promoted to non-nullable
+    assertNoEdge(iNode, never);
+    // But there is an edge from j to `never`.
+    assertEdge(jNode, never, hard: true);
+  }
+
   test_topLevelVar_initializer() async {
     await analyze('''
 bool b1 = true;
@@ -676,6 +1114,29 @@
     // top level variable doesn't cause flow analysis to crash.
   }
 
+  test_try_falls_through_to_after_try() async {
+    await analyze('''
+void f(int i) {
+  try {
+    g(i);
+    if (i == null) return;
+  } catch (_) {
+    return;
+  }
+  h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+    var iNode = decoratedTypeAnnotation('int i').node;
+    var jNode = decoratedTypeAnnotation('int j').node;
+    var kNode = decoratedTypeAnnotation('int k').node;
+    // No edge from i to k because i's type is promoted to non-nullable
+    assertNoEdge(iNode, kNode);
+    // But there is an edge from i to j.
+    assertEdge(iNode, jNode, hard: true);
+  }
+
   test_while_break_target() async {
     await analyze('''
 void f(int i) {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index fa14641..079cf85 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -48,8 +48,8 @@
     var typeProvider = TestTypeProvider();
     var graph = NullabilityGraphForTesting();
     var decoratedClassHierarchy = _DecoratedClassHierarchyForTesting();
-    var checker = AssignmentCheckerForTesting(
-        Dart2TypeSystem(typeProvider), graph, decoratedClassHierarchy);
+    var checker = AssignmentCheckerForTesting(Dart2TypeSystem(typeProvider),
+        typeProvider, graph, decoratedClassHierarchy);
     var assignmentCheckerTest =
         AssignmentCheckerTest._(typeProvider, graph, checker);
     decoratedClassHierarchy.assignmentCheckerTest = assignmentCheckerTest;
@@ -83,7 +83,7 @@
     var t = list(object());
     assign(bottom, t);
     assertEdge(never, t.node, hard: false);
-    expect(graph.getUpstreamEdges(t.typeArguments[0].node), isEmpty);
+    assertNoEdge(anyNode, t.typeArguments[0].node);
   }
 
   void test_bottom_to_simple() {
@@ -165,11 +165,19 @@
     assertEdge(t1.returnType.node, t2.returnType.node, hard: false);
   }
 
+  void test_future_int_to_future_or_int() {
+    var t1 = future(int_());
+    var t2 = futureOr(int_());
+    assign(t1, t2, hard: true);
+    assertEdge(t1.node, t2.node, hard: true);
+    assertEdge(t1.typeArguments[0].node, t2.typeArguments[0].node, hard: false);
+  }
+
   test_generic_to_dynamic() {
     var t = list(object());
     assign(t, dynamic_);
     assertEdge(t.node, always, hard: false);
-    expect(graph.getDownstreamEdges(t.typeArguments[0].node), isEmpty);
+    assertNoEdge(t.typeArguments[0].node, anyNode);
   }
 
   test_generic_to_generic_downcast() {
@@ -185,10 +193,7 @@
     // - the supertype of MyListOfList<T> is List<List<T?C>>
     var c = _myListOfListSupertype.typeArguments[0].typeArguments[0].node;
     // Then there should be an edge from b to substitute(a, c)
-    var substitutionNode = graph.getDownstreamEdges(b).single.destinationNode
-        as NullabilityNodeForSubstitution;
-    expect(substitutionNode.innerNode, same(a));
-    expect(substitutionNode.outerNode, same(c));
+    assertEdge(b, substitutionNode(a, c), hard: false);
   }
 
   test_generic_to_generic_same_element() {
@@ -212,10 +217,7 @@
     // - the supertype of MyListOfList<T> is List<List<T?C>>
     var c = _myListOfListSupertype.typeArguments[0].typeArguments[0].node;
     // Then there should be an edge from substitute(a, c) to b.
-    var substitutionNode = graph.getUpstreamEdges(b).single.primarySource
-        as NullabilityNodeForSubstitution;
-    expect(substitutionNode.innerNode, same(a));
-    expect(substitutionNode.outerNode, same(c));
+    assertEdge(substitutionNode(a, c), b, hard: false);
   }
 
   test_generic_to_object() {
@@ -223,21 +225,36 @@
     var t2 = object();
     assign(t1, t2);
     assertEdge(t1.node, t2.node, hard: false);
-    expect(graph.getDownstreamEdges(t1.typeArguments[0].node), isEmpty);
+    assertNoEdge(t1.typeArguments[0].node, anyNode);
   }
 
   test_generic_to_void() {
     var t = list(object());
     assign(t, void_);
     assertEdge(t.node, always, hard: false);
-    expect(graph.getDownstreamEdges(t.typeArguments[0].node), isEmpty);
+    assertNoEdge(t.typeArguments[0].node, anyNode);
+  }
+
+  void test_int_to_future_or_int() {
+    var t1 = int_();
+    var t2 = futureOr(int_());
+    assign(t1, t2, hard: true);
+    // Note: given code like:
+    //   int x = null;
+    //   FutureOr<int> y = x;
+    // There are two possible migrations for `FutureOr<int>`: we could change it
+    // to either `FutureOr<int?>` or `FutureOr<int>?`.  We choose to do
+    // `FutureOr<int>?` because it is a narrower type, so it is less likely to
+    // cause a proliferation of nullable types in the user's program.
+    assertEdge(t1.node, t2.node, hard: true);
+    assertNoEdge(t1.node, t2.typeArguments[0].node);
   }
 
   void test_null_to_generic() {
     var t = list(object());
     assign(null_, t);
     assertEdge(always, t.node, hard: false);
-    expect(graph.getUpstreamEdges(t.typeArguments[0].node), isEmpty);
+    assertNoEdge(anyNode, t.typeArguments[0].node);
   }
 
   void test_null_to_simple() {
@@ -330,7 +347,7 @@
     // upstream from it.
     if (node == never) return;
 
-    for (var edge in graph.getUpstreamEdges(node)) {
+    for (var edge in getEdges(anyNode, node)) {
       expect(edge.primarySource, never);
     }
   }
@@ -358,6 +375,42 @@
     return variables.decoratedExpressionType(findNode.expression(text));
   }
 
+  test_as_dynamic() async {
+    await analyze('''
+void f(Object o) {
+  (o as dynamic).gcd(1);
+}
+''');
+    assertEdge(decoratedTypeAnnotation('Object o').node,
+        decoratedTypeAnnotation('dynamic').node,
+        hard: true);
+    // TODO(mfairhurst): these should probably be hard edges.
+    assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: false);
+  }
+
+  test_as_int() async {
+    await analyze('''
+void f(Object o) {
+  (o as int).gcd(1);
+}
+''');
+    assertEdge(decoratedTypeAnnotation('Object o').node,
+        decoratedTypeAnnotation('int').node,
+        hard: true);
+    // TODO(mfairhurst): these should probably be hard edges.
+    assertEdge(decoratedTypeAnnotation('int').node, never, hard: false);
+  }
+
+  test_already_migrated_field() async {
+    await analyze('''
+double f() => double.NAN;
+''');
+    var nanElement = typeProvider.doubleType.element.getField('NAN');
+    assertEdge(variables.decoratedElementType(nanElement).node,
+        decoratedTypeAnnotation('double f').node,
+        hard: false);
+  }
+
   test_assert_demonstrates_non_null_intent() async {
     await analyze('''
 void f(int i) {
@@ -384,6 +437,100 @@
         hard: false);
   }
 
+  test_assign_dynamic_to_other_type() async {
+    await analyze('''
+int f(dynamic d) => d;
+''');
+    // There is no explicit null check necessary, since `dynamic` is
+    // downcastable to any type, nullable or not.
+    expect(checkExpression('d;'), isNull);
+    // But we still create an edge, to make sure that the possibility of `null`
+    // propagates to callees.
+    assertEdge(decoratedTypeAnnotation('dynamic').node,
+        decoratedTypeAnnotation('int').node,
+        hard: true);
+  }
+
+  test_assign_function_type_to_function_interface_type() async {
+    await analyze('''
+Function f(void Function() x) => x;
+''');
+    assertEdge(decoratedGenericFunctionTypeAnnotation('void Function()').node,
+        decoratedTypeAnnotation('Function f').node,
+        hard: true);
+  }
+
+  test_assign_future_to_futureOr_complex() async {
+    await analyze('''
+import 'dart:async';
+FutureOr<List<int>> f(Future<List<int>> x) => x;
+''');
+    // If `x` is `Future<List<int?>>`, then the only way to migrate is to make
+    // the return type `FutureOr<List<int?>>`.
+    assertEdge(decoratedTypeAnnotation('int>> x').node,
+        decoratedTypeAnnotation('int>> f').node,
+        hard: false);
+    assertNoEdge(decoratedTypeAnnotation('int>> x').node,
+        decoratedTypeAnnotation('List<int>> f').node);
+    assertNoEdge(decoratedTypeAnnotation('int>> x').node,
+        decoratedTypeAnnotation('FutureOr<List<int>> f').node);
+  }
+
+  test_assign_future_to_futureOr_simple() async {
+    await analyze('''
+import 'dart:async';
+FutureOr<int> f(Future<int> x) => x;
+''');
+    // If `x` is nullable, then there are two migrations possible: we could make
+    // the return type `FutureOr<int?>` or we could make it `FutureOr<int>?`.
+    // We choose `FutureOr<int>?` because it's strictly more conservative (it's
+    // a subtype of `FutureOr<int?>`).
+    assertEdge(decoratedTypeAnnotation('Future<int> x').node,
+        decoratedTypeAnnotation('FutureOr<int>').node,
+        hard: true);
+    assertNoEdge(decoratedTypeAnnotation('Future<int> x').node,
+        decoratedTypeAnnotation('int> f').node);
+    // If `x` is `Future<int?>`, then the only way to migrate is to make the
+    // return type `FutureOr<int?>`.
+    assertEdge(substitutionNode(decoratedTypeAnnotation('int> x').node, never),
+        decoratedTypeAnnotation('int> f').node,
+        hard: false);
+    assertNoEdge(decoratedTypeAnnotation('int> x').node,
+        decoratedTypeAnnotation('FutureOr<int>').node);
+  }
+
+  test_assign_non_future_to_futureOr_complex() async {
+    await analyze('''
+import 'dart:async';
+FutureOr<List<int>> f(List<int> x) => x;
+''');
+    // If `x` is `List<int?>`, then the only way to migrate is to make the
+    // return type `FutureOr<List<int?>>`.
+    assertEdge(decoratedTypeAnnotation('int> x').node,
+        decoratedTypeAnnotation('int>> f').node,
+        hard: false);
+    assertNoEdge(decoratedTypeAnnotation('int> x').node,
+        decoratedTypeAnnotation('List<int>> f').node);
+    assertNoEdge(decoratedTypeAnnotation('int> x').node,
+        decoratedTypeAnnotation('FutureOr<List<int>> f').node);
+  }
+
+  test_assign_non_future_to_futureOr_simple() async {
+    await analyze('''
+import 'dart:async';
+FutureOr<int> f(int x) => x;
+''');
+    // If `x` is nullable, then there are two migrations possible: we could make
+    // the return type `FutureOr<int?>` or we could make it `FutureOr<int>?`.
+    // We choose `FutureOr<int>?` because it's strictly more conservative (it's
+    // a subtype of `FutureOr<int?>`).
+    assertEdge(decoratedTypeAnnotation('int x').node,
+        decoratedTypeAnnotation('FutureOr<int>').node,
+        hard: true);
+    assertNoEdge(decoratedTypeAnnotation('int x').node,
+        decoratedTypeAnnotation('int>').node);
+  }
+
   test_assign_null_to_generic_type() async {
     await analyze('''
 main() {
@@ -421,12 +568,76 @@
     var iterableInt = decoratedTypeAnnotation('Iterable<int>');
     var listInt = decoratedTypeAnnotation('List<int>');
     assertEdge(listInt.node, iterableInt.node, hard: true);
-    var substitution = graph
-        .getUpstreamEdges(iterableInt.typeArguments[0].node)
-        .single
-        .primarySource as NullabilityNodeForSubstitution;
-    expect(substitution.innerNode, same(listInt.typeArguments[0].node));
-    expect(substitution.outerNode, same(never));
+    assertEdge(substitutionNode(listInt.typeArguments[0].node, never),
+        iterableInt.typeArguments[0].node,
+        hard: false);
+  }
+
+  test_assignmentExpression_compound_dynamic() async {
+    await analyze('''
+void f(dynamic x, int y) {
+  x += y;
+}
+''');
+    // No assertions; just making sure this doesn't crash.
+  }
+
+  test_assignmentExpression_compound_simple() async {
+    var code = '''
+abstract class C {
+  C operator+(C x);
+}
+C f(C y, C z) => (y += z);
+''';
+    await analyze(code);
+    var targetEdge =
+        assertEdge(decoratedTypeAnnotation('C y').node, never, hard: true);
+    expect((targetEdge.origin as CompoundAssignmentOrigin).offset,
+        code.indexOf('+='));
+    assertNullCheck(
+        checkExpression('z);'),
+        assertEdge(decoratedTypeAnnotation('C z').node,
+            decoratedTypeAnnotation('C x').node,
+            hard: true));
+    var operatorReturnEdge = assertEdge(
+        decoratedTypeAnnotation('C operator').node,
+        decoratedTypeAnnotation('C y').node,
+        hard: false);
+    expect((operatorReturnEdge.origin as CompoundAssignmentOrigin).offset,
+        code.indexOf('+='));
+    var fReturnEdge = assertEdge(decoratedTypeAnnotation('C operator').node,
+        decoratedTypeAnnotation('C f').node,
+        hard: false);
+    assertNullCheck(checkExpression('(y += z)'), fReturnEdge);
+  }
+
+  test_assignmentExpression_compound_withSubstitution() async {
+    var code = '''
+abstract class C<T> {
+  C<T> operator+(C<T> x);
+}
+C<int> f(C<int> y, C<int> z) => (y += z);
+''';
+    await analyze(code);
+    var targetEdge =
+        assertEdge(decoratedTypeAnnotation('C<int> y').node, never, hard: true);
+    expect((targetEdge.origin as CompoundAssignmentOrigin).offset,
+        code.indexOf('+='));
+    assertNullCheck(
+        checkExpression('z);'),
+        assertEdge(decoratedTypeAnnotation('C<int> z').node,
+            decoratedTypeAnnotation('C<T> x').node,
+            hard: true));
+    var operatorReturnEdge = assertEdge(
+        decoratedTypeAnnotation('C<T> operator').node,
+        decoratedTypeAnnotation('C<int> y').node,
+        hard: false);
+    expect((operatorReturnEdge.origin as CompoundAssignmentOrigin).offset,
+        code.indexOf('+='));
+    var fReturnEdge = assertEdge(decoratedTypeAnnotation('C<T> operator').node,
+        decoratedTypeAnnotation('C<int> f').node,
+        hard: false);
+    assertNullCheck(checkExpression('(y += z)'), fReturnEdge);
   }
 
   test_assignmentExpression_field() async {
@@ -1362,6 +1573,15 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('double').node);
   }
 
+  test_export_metadata() async {
+    await analyze('''
+@deprecated
+export 'dart:async';
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
   test_field_metadata() async {
     await analyze('''
 class A {
@@ -1435,6 +1655,66 @@
         decoratedTypeAnnotation('int i').node);
   }
 
+  test_for_element_list() async {
+    await analyze('''
+void f(List<int> ints) {
+  <int>[for(int i in ints) i];
+}
+''');
+
+    assertNullCheck(
+        checkExpression('ints) i'),
+        assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+            hard: true));
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+  }
+
+  test_for_element_map() async {
+    await analyze('''
+void f(List<String> strs, List<int> ints) {
+  <String, int>{
+    for (String s in strs)
+      for (int i in ints)
+        s: i,
+  };
+}
+''');
+
+    assertNullCheck(
+        checkExpression('strs)\n'),
+        assertEdge(decoratedTypeAnnotation('List<String> strs').node, never,
+            hard: true));
+    assertNullCheck(
+        checkExpression('ints)\n'),
+        assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+            hard: false));
+
+    var keyTypeNode = decoratedTypeAnnotation('String, int>{').node;
+    var valueTypeNode = decoratedTypeAnnotation('int>{').node;
+    assertEdge(decoratedTypeAnnotation('String s').node, keyTypeNode,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int i').node, valueTypeNode,
+        hard: false);
+  }
+
+  test_for_element_set() async {
+    await analyze('''
+void f(List<int> ints) {
+  <int>{for(int i in ints) i};
+}
+''');
+
+    assertNullCheck(
+        checkExpression('ints) i'),
+        assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+            hard: true));
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int>{').node,
+        hard: false);
+  }
+
   test_for_with_declaration() async {
     await analyze('''
 main() {
@@ -1673,6 +1953,74 @@
             hard: false));
   }
 
+  test_genericMethodInvocation() async {
+    await analyze('''
+class Base {
+  T foo<T>(T x) => x;
+}
+class Derived extends Base {}
+int bar(Derived d, int i) => d.foo(i);
+''');
+    var implicitTypeArgumentMatcher = anyNode;
+    assertEdge(
+        decoratedTypeAnnotation('int i').node,
+        substitutionNode(
+            implicitTypeArgumentMatcher, decoratedTypeAnnotation('T x').node),
+        hard: true);
+    var implicitTypeArgumentNullability =
+        implicitTypeArgumentMatcher.matchingNode;
+    assertEdge(
+        substitutionNode(implicitTypeArgumentNullability,
+            decoratedTypeAnnotation('T foo').node),
+        decoratedTypeAnnotation('int bar').node,
+        hard: false);
+  }
+
+  test_genericMethodInvocation_withBoundSubstitution() async {
+    await analyze('''
+class Base<T> {
+  U foo<U extends T>(U x) => x;
+}
+class Derived<V> extends Base<Iterable<V>> {}
+bar(Derived<int> d, List<int> x) => d.foo(x);
+''');
+    // Don't bother checking any edges; the assertions in the DecoratedType
+    // constructor verify that we've substituted the bound correctly.
+  }
+
+  test_genericMethodInvocation_withSubstitution() async {
+    await analyze('''
+class Base<T> {
+  U foo<U>(U x, T y) => x;
+}
+class Derived<V> extends Base<List<V>> {}
+int bar(Derived<String> d, int i, List<String> j) => d.foo(i, j);
+''');
+    assertEdge(
+        decoratedTypeAnnotation('String> j').node,
+        substitutionNode(decoratedTypeAnnotation('String> d').node,
+            decoratedTypeAnnotation('V>>').node),
+        hard: false);
+    assertEdge(
+        decoratedTypeAnnotation('List<String> j').node,
+        substitutionNode(decoratedTypeAnnotation('List<V>>').node,
+            decoratedTypeAnnotation('T y').node),
+        hard: true);
+    var implicitTypeArgumentMatcher = anyNode;
+    assertEdge(
+        decoratedTypeAnnotation('int i').node,
+        substitutionNode(
+            implicitTypeArgumentMatcher, decoratedTypeAnnotation('U x').node),
+        hard: true);
+    var implicitTypeArgumentNullability =
+        implicitTypeArgumentMatcher.matchingNode;
+    assertEdge(
+        substitutionNode(implicitTypeArgumentNullability,
+            decoratedTypeAnnotation('U foo').node),
+        decoratedTypeAnnotation('int bar').node,
+        hard: false);
+  }
+
   test_if_condition() async {
     await analyze('''
 void f(bool b) {
@@ -1685,22 +2033,41 @@
   }
 
   test_if_conditional_control_flow_after() async {
-    // Asserts after ifs don't demonstrate non-null intent.
-    // TODO(paulberry): if both branches complete normally, they should.
     await analyze('''
-void f(bool b, int i) {
+void f(bool b, int i, int j) {
+  assert(j != null);
   if (b) return;
   assert(i != null);
 }
 ''');
 
-    assertNoEdge(always, decoratedTypeAnnotation('int i').node);
+    // Asserts after ifs don't demonstrate non-null intent.
+    assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+    // But asserts before ifs do
+    assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
+  }
+
+  test_if_conditional_control_flow_after_normal_completion() async {
+    await analyze('''
+void f(bool b1, bool b2, int i, int j) {
+  if (b1) {}
+  assert(j != null);
+  if (b2) return;
+  assert(i != null);
+}
+''');
+
+    // Asserts after `if (...) return` s don't demonstrate non-null intent.
+    assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+    // But asserts after `if (...) {}` do, since both branches of the `if`
+    // complete normally, so the assertion is unconditionally reachable.
+    assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
   }
 
   test_if_conditional_control_flow_within() async {
-    // Asserts inside ifs don't demonstrate non-null intent.
     await analyze('''
-void f(bool b, int i) {
+void f(bool b, int i, int j) {
+  assert(j != null);
   if (b) {
     assert(i != null);
   } else {
@@ -1709,26 +2076,10 @@
 }
 ''');
 
-    assertNoEdge(always, decoratedTypeAnnotation('int i').node);
-  }
-
-  test_if_element() async {
-    await analyze('''
-void f(bool b) {
-  int i1 = null;
-  int i2 = null;
-  <int>[if (b) i1 else i2];
-}
-''');
-
-    assertNullCheck(checkExpression('b) i1'),
-        assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
-    assertEdge(decoratedTypeAnnotation('int i1').node,
-        decoratedTypeAnnotation('int>[').node,
-        hard: false);
-    assertEdge(decoratedTypeAnnotation('int i2').node,
-        decoratedTypeAnnotation('int>[').node,
-        hard: false);
+    // Asserts inside ifs don't demonstrate non-null intent.
+    assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+    // But asserts outside ifs do.
+    assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
   }
 
   @failingTest
@@ -1755,6 +2106,51 @@
     expect(discard.pureCondition, true);
   }
 
+  test_if_element_list() async {
+    await analyze('''
+void f(bool b) {
+  int i1 = null;
+  int i2 = null;
+  <int>[if (b) i1 else i2];
+}
+''');
+
+    assertNullCheck(checkExpression('b) i1'),
+        assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+    assertEdge(decoratedTypeAnnotation('int i1').node,
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int i2').node,
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+  }
+
+  test_if_element_map() async {
+    await analyze('''
+void f(bool b) {
+  int i1 = null;
+  int i2 = null;
+  String s1 = null;
+  String s2 = null;
+  <String, int>{if (b) s1: i1 else s2: i2};
+}
+''');
+
+    assertNullCheck(checkExpression('b) s1'),
+        assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+
+    var keyTypeNode = decoratedTypeAnnotation('String, int>{').node;
+    var valueTypeNode = decoratedTypeAnnotation('int>{').node;
+    assertEdge(decoratedTypeAnnotation('String s1').node, keyTypeNode,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('String s2').node, keyTypeNode,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int i1').node, valueTypeNode,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int i2').node, valueTypeNode,
+        hard: false);
+  }
+
   test_if_element_nested() async {
     await analyze('''
 void f(bool b1, bool b2) {
@@ -1782,6 +2178,25 @@
         hard: false);
   }
 
+  test_if_element_set() async {
+    await analyze('''
+void f(bool b) {
+  int i1 = null;
+  int i2 = null;
+  <int>{if (b) i1 else i2};
+}
+''');
+
+    assertNullCheck(checkExpression('b) i1'),
+        assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+    assertEdge(decoratedTypeAnnotation('int i1').node,
+        decoratedTypeAnnotation('int>{').node,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int i2').node,
+        decoratedTypeAnnotation('int>{').node,
+        hard: false);
+  }
+
   test_if_guard_equals_null() async {
     await analyze('''
 int f(int i, int j, int k) {
@@ -1844,6 +2259,26 @@
         assertEdge(nullable_i, nullable_return, hard: false));
   }
 
+  test_import_metadata() async {
+    await analyze('''
+@deprecated
+import 'dart:async';
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
+  test_indexExpression_dynamic() async {
+    await analyze('''
+int f(dynamic d, int i) {
+  return d[i];
+}
+''');
+    // We assume that the index expression might evaluate to anything, including
+    // `null`.
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+  }
+
   test_indexExpression_index() async {
     await analyze('''
 class C {
@@ -1932,6 +2367,33 @@
         hard: false);
   }
 
+  test_instanceCreation_generic_dynamic() async {
+    await analyze('''
+class C<T> {}
+C<Object> f() => C<dynamic>();
+''');
+    assertEdge(decoratedTypeAnnotation('dynamic').node,
+        decoratedTypeAnnotation('Object').node,
+        hard: false);
+  }
+
+  test_instanceCreation_generic_inferredParameterType() async {
+    await analyze('''
+class C<T> {
+  C(List<T> x);
+}
+C<int> f(List<int> x) => C(x);
+''');
+    var edge = assertEdge(anyNode, decoratedTypeAnnotation('int> f').node,
+        hard: false);
+    var inferredTypeArgument = edge.primarySource;
+    assertEdge(
+        decoratedTypeAnnotation('int> x').node,
+        substitutionNode(
+            inferredTypeArgument, decoratedTypeAnnotation('T> x').node),
+        hard: false);
+  }
+
   test_instanceCreation_generic_parameter() async {
     await analyze('''
 class C<T> {
@@ -1951,6 +2413,25 @@
         assertEdge(nullable_i, nullable_c_t_or_nullable_t, hard: true));
   }
 
+  test_instanceCreation_generic_parameter_named() async {
+    await analyze('''
+class C<T> {
+  C({T t});
+}
+f(int i) => C<int>(t: i/*check*/);
+''');
+    var nullable_i = decoratedTypeAnnotation('int i').node;
+    var nullable_c_t = decoratedTypeAnnotation('C<int>').typeArguments[0].node;
+    var nullable_t = decoratedTypeAnnotation('T t').node;
+    var check_i = checkExpression('i/*check*/');
+    var nullable_c_t_or_nullable_t =
+        check_i.edges.single.destinationNode as NullabilityNodeForSubstitution;
+    expect(nullable_c_t_or_nullable_t.innerNode, same(nullable_c_t));
+    expect(nullable_c_t_or_nullable_t.outerNode, same(nullable_t));
+    assertNullCheck(check_i,
+        assertEdge(nullable_i, nullable_c_t_or_nullable_t, hard: true));
+  }
+
   test_instanceCreation_parameter_named_optional() async {
     await analyze('''
 class C {
@@ -2028,6 +2509,15 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('bool').node);
   }
 
+  test_library_metadata() async {
+    await analyze('''
+@deprecated
+library foo;
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
   test_libraryDirective() async {
     await analyze('''
 library foo;
@@ -2035,31 +2525,38 @@
     // Passes if no exceptions are thrown.
   }
 
-  @failingTest
   test_listLiteral_noTypeArgument_noNullableElements() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 List<String> f() {
   return ['a', 'b'];
 }
 ''');
     assertNoUpstreamNullability(decoratedTypeAnnotation('List').node);
-    // TODO(brianwilkerson) Add an assertion that there is an edge from the list
-    //  literal's fake type argument to the return type's type argument.
+    final returnTypeNode = decoratedTypeAnnotation('String').node;
+    final returnTypeEdges = getEdges(anyNode, returnTypeNode);
+
+    expect(returnTypeEdges.length, 1);
+    final returnTypeEdge = returnTypeEdges.single;
+
+    final listArgType = returnTypeEdge.primarySource;
+    assertNoUpstreamNullability(listArgType);
   }
 
-  @failingTest
   test_listLiteral_noTypeArgument_nullableElement() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 List<String> f() {
   return ['a', null, 'c'];
 }
 ''');
     assertNoUpstreamNullability(decoratedTypeAnnotation('List').node);
-    assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
+    final returnTypeNode = decoratedTypeAnnotation('String').node;
+    final returnTypeEdges = getEdges(anyNode, returnTypeNode);
+
+    expect(returnTypeEdges.length, 1);
+    final returnTypeEdge = returnTypeEdges.single;
+
+    final listArgType = returnTypeEdge.primarySource;
+    assertEdge(always, listArgType, hard: false);
   }
 
   test_listLiteral_typeArgument_noNullableElements() async {
@@ -2175,6 +2672,47 @@
     assertEdge(decoratedTypeAnnotation('int k').node, never, hard: true);
   }
 
+  test_methodInvocation_dynamic() async {
+    await analyze('''
+class C {
+  int g(int i) => i;
+}
+int f(dynamic d, int j) {
+  return d.g(j);
+}
+''');
+    // The call `d.g(j)` is dynamic, so we can't tell what method it resolves
+    // to.  There's no reason to assume it resolves to `C.g`.
+    assertNoEdge(decoratedTypeAnnotation('int j').node,
+        decoratedTypeAnnotation('int i').node);
+    assertNoEdge(decoratedTypeAnnotation('int g').node,
+        decoratedTypeAnnotation('int f').node);
+    // We do, however, assume that it might return anything, including `null`.
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+  }
+
+  test_methodInvocation_object_method() async {
+    await analyze('''
+String f(int i) => i.toString();
+''');
+    // No edge from i to `never` because it is safe to call `toString` on
+    // `null`.
+    assertNoEdge(decoratedTypeAnnotation('int').node, never);
+  }
+
+  test_methodInvocation_object_method_on_non_interface_type() async {
+    await analyze('''
+String f(void Function() g) => g.toString();
+''');
+    var toStringReturnType = variables
+        .decoratedElementType(
+            typeProvider.objectType.element.getMethod('toString'))
+        .returnType;
+    assertEdge(
+        toStringReturnType.node, decoratedTypeAnnotation('String f').node,
+        hard: false);
+  }
+
   test_methodInvocation_parameter_contravariant() async {
     await analyze('''
 class C<T> {
@@ -2351,6 +2889,21 @@
     assertEdge(lubNode, decoratedTypeAnnotation('bool f').node, hard: false);
   }
 
+  test_methodInvocation_static_on_generic_class() async {
+    await analyze('''
+class C<T> {
+  static int f(int x) => 0;
+}
+int g(int y) => C.f(y);
+''');
+    assertEdge(decoratedTypeAnnotation('int y').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('int f').node,
+        decoratedTypeAnnotation('int g').node,
+        hard: false);
+  }
+
   test_methodInvocation_target_check() async {
     await analyze('''
 class C {
@@ -2405,6 +2958,95 @@
     assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
   }
 
+  test_methodInvocation_target_generic_in_base_class() async {
+    await analyze('''
+abstract class B<T> {
+  void m(T/*1*/ t);
+}
+abstract class C extends B<int/*2*/> {}
+void f(C c, int/*3*/ i) {
+  c.m(i);
+}
+''');
+    // nullable(3) -> substitute(nullable(2), nullable(1))
+    var nullable1 = decoratedTypeAnnotation('T/*1*/').node;
+    var nullable2 = decoratedTypeAnnotation('int/*2*/').node;
+    var nullable3 = decoratedTypeAnnotation('int/*3*/').node;
+    assertEdge(nullable3, substitutionNode(nullable2, nullable1), hard: true);
+  }
+
+  test_methodInvocation_typeParameter_inferred() async {
+    await analyze('''
+T f<T>(T t) => t;
+void g() {
+  int y;
+  int x = f(y);
+}
+''');
+    var int_y = decoratedTypeAnnotation('int y').node;
+    var int_x = decoratedTypeAnnotation('int x').node;
+    var t_ret = decoratedTypeAnnotation('T f').node;
+    var t_param = decoratedTypeAnnotation('T t').node;
+
+    assertEdge(substitutionNode(anyNode, t_ret), int_x, hard: false);
+    assertEdge(int_y, substitutionNode(anyNode, t_param), hard: true);
+    assertEdge(t_param, t_ret, hard: true);
+  }
+
+  @failingTest
+  test_methodInvocation_typeParameter_inferred_inGenericClass() async {
+    // this creates an edge case because the typeArguments are not equal in
+    // length the the typeFormals of the calleeType, due to the enclosing
+    // generic class.
+    await analyze('''
+class C<T> {
+ void g() {
+   // use a local fn because generic methods aren't implemented.
+   T f<T>(T t) => t;
+   int y;
+   int x = f(y);
+ }
+}
+''');
+    var int_y = decoratedTypeAnnotation('int y').node;
+    var int_x = decoratedTypeAnnotation('int x').node;
+    var t_ret = decoratedTypeAnnotation('T f').node;
+    var t_param = decoratedTypeAnnotation('T t').node;
+
+    assertEdge(int_y, t_param, hard: true);
+    assertEdge(t_param, t_ret, hard: true);
+    assertEdge(t_ret, int_x, hard: false);
+  }
+
+  @failingTest
+  test_methodInvocation_typeParameter_inferred_inGenericExtreme() async {
+    // this creates an edge case because the typeArguments are not equal in
+    // length the the typeFormals of the calleeType, due to the enclosing
+    // generic class/functions.
+    await analyze('''
+class C<T> {
+ void g() {
+   // use local fns because generic methods aren't implemented.
+   void f2<R1>() {
+     void f3<R2>() {
+       T f<T>(T t) => t;
+       int y;
+       int x = f(y);
+     }
+   }
+ }
+}
+''');
+    var int_y = decoratedTypeAnnotation('int y').node;
+    var int_x = decoratedTypeAnnotation('int x').node;
+    var t_ret = decoratedTypeAnnotation('T f').node;
+    var t_param = decoratedTypeAnnotation('T t').node;
+
+    assertEdge(int_y, t_param, hard: true);
+    assertEdge(t_param, t_ret, hard: true);
+    assertEdge(t_ret, int_x, hard: false);
+  }
+
   test_never() async {
     await analyze('');
 
@@ -2572,6 +3214,62 @@
         assertEdge(always, decoratedTypeAnnotation('int').node, hard: false));
   }
 
+  test_part_metadata() async {
+    var pathContext = resourceProvider.pathContext;
+    addSource(pathContext.join(pathContext.dirname(testFile), 'part.dart'), '''
+part of test;
+''');
+    await analyze('''
+library test;
+@deprecated
+part 'part.dart';
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
+  test_part_of_identifier() async {
+    var pathContext = resourceProvider.pathContext;
+    var testFileName = pathContext.basename(testFile);
+    addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+library test;
+part '$testFileName';
+''');
+    await analyze('''
+part of test;
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
+  test_part_of_metadata() async {
+    var pathContext = resourceProvider.pathContext;
+    var testFileName = pathContext.basename(testFile);
+    addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+library test;
+part '$testFileName';
+''');
+    await analyze('''
+@deprecated
+part of test;
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
+  test_part_of_path() async {
+    var pathContext = resourceProvider.pathContext;
+    var testFileName = pathContext.basename(testFile);
+    addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+part '$testFileName';
+''');
+    await analyze('''
+part of 'lib.dart';
+''');
+    // No assertions needed; the AnnotationTracker mixin verifies that the
+    // metadata was visited.
+  }
+
   test_postDominators_assert() async {
     await analyze('''
 void test(bool b1, bool b2, bool b3, bool _b) {
@@ -2588,6 +3286,18 @@
     assertEdge(decoratedTypeAnnotation('bool b3').node, never, hard: true);
   }
 
+  test_postDominators_assignment_with_same_var_on_lhs_and_in_rhs() async {
+    await analyze('''
+void f(int i) {
+  i = g(i);
+}
+int g(int j) => 0;
+''');
+    assertEdge(decoratedTypeAnnotation('int i').node,
+        decoratedTypeAnnotation('int j').node,
+        hard: true);
+  }
+
   test_postDominators_break() async {
     await analyze('''
 class C {
@@ -2953,6 +3663,22 @@
     assertEdge(always, decoratedTypeAnnotation('int i').node, hard: false);
   }
 
+  test_postDominators_questionQuestionOperator() async {
+    await analyze('''
+class C {
+  Object m() => null;
+}
+Object test(C x, C y) => x.m() ?? y.m();
+''');
+    // There is a hard edge from x to `never` because `x.m()` is unconditionally
+    // reachable from the top of `test`.
+    assertEdge(decoratedTypeAnnotation('C x').node, never, hard: true);
+    // However, the edge from y to `never` is soft because `y.m()` is only
+    // executed if `x.m()` returned `null`.
+    assertEdge(decoratedTypeAnnotation('C y').node, never,
+        hard: false, guards: [decoratedTypeAnnotation('Object m').node]);
+  }
+
   test_postDominators_reassign() async {
     await analyze('''
 void test(bool b, int i1, int i2) {
@@ -3080,6 +3806,19 @@
         assertEdge(decoratedTypeAnnotation('C c3').node, never, hard: false));
   }
 
+  test_postDominators_tryCatch() async {
+    await analyze('''
+void test(int i) {
+  try {} catch (_) {
+    i.isEven;
+  }
+}
+''');
+    // Edge should not be hard because the call to `i.isEven` does not
+    // post-dominate the declaration of `i`.
+    assertEdge(decoratedTypeAnnotation('int i').node, never, hard: false);
+  }
+
   test_postDominators_whileStatement_unconditional() async {
     await analyze('''
 class C {
@@ -3160,6 +3899,24 @@
         hard: false);
   }
 
+  test_prefixedIdentifier_getter_type_in_generic() async {
+    await analyze('''
+class C<T> {
+  List<T> _x;
+  List<T> get x => _x;
+}
+List<int> f(C<int> c) => c.x;
+''');
+    assertEdge(decoratedTypeAnnotation('List<T> get').node,
+        decoratedTypeAnnotation('List<int> f').node,
+        hard: false);
+    assertEdge(
+        substitutionNode(decoratedTypeAnnotation('int> c').node,
+            decoratedTypeAnnotation('T> get').node),
+        decoratedTypeAnnotation('int> f').node,
+        hard: false);
+  }
+
   test_prefixedIdentifier_target_check() async {
     await analyze('''
 class C {
@@ -3262,6 +4019,32 @@
     assertEdge(never, returnType, hard: false);
   }
 
+  test_propertyAccess_dynamic() async {
+    await analyze('''
+class C {
+  int get g => 0;
+}
+int f(dynamic d) {
+  return d.g;
+}
+''');
+    // The call `d.g` is dynamic, so we can't tell what method it resolves
+    // to.  There's no reason to assume it resolves to `C.g`.
+    assertNoEdge(decoratedTypeAnnotation('int get g').node,
+        decoratedTypeAnnotation('int f').node);
+    // We do, however, assume that it might return anything, including `null`.
+    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+  }
+
+  test_propertyAccess_object_property() async {
+    await analyze('''
+int f(int i) => i.hashCode;
+''');
+    // No edge from i to `never` because it is safe to call `hashCode` on
+    // `null`.
+    assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+  }
+
   test_propertyAccess_return_type() async {
     await analyze('''
 class C {
@@ -3288,6 +4071,18 @@
     assertEdge(lubNode, decoratedTypeAnnotation('bool f').node, hard: false);
   }
 
+  test_propertyAccess_static_on_generic_class() async {
+    await analyze('''
+class C<T> {
+  static int x = 1;
+}
+int f() => C.x;
+''');
+    assertEdge(decoratedTypeAnnotation('int x').node,
+        decoratedTypeAnnotation('int f').node,
+        hard: false);
+  }
+
   test_propertyAccess_target_check() async {
     await analyze('''
 class C {
@@ -3331,13 +4126,8 @@
     var nullable_t1 = decoratedTypeAnnotation('T/*1*/').node;
     var nullable_t2 = decoratedTypeAnnotation('T/*2*/').node;
     var nullable_u3 = decoratedTypeAnnotation('U/*3*/').node;
-    var nullable_t2_or_nullable_u3 = graph
-        .getDownstreamEdges(nullable_t1)
-        .single
-        .destinationNode as NullabilityNodeForSubstitution;
-    expect(nullable_t2_or_nullable_u3.innerNode, same(nullable_t2));
-    expect(nullable_t2_or_nullable_u3.outerNode, same(nullable_u3));
-    assertEdge(nullable_t1, nullable_t2_or_nullable_u3, hard: true);
+    assertEdge(nullable_t1, substitutionNode(nullable_t2, nullable_u3),
+        hard: true);
   }
 
   test_redirecting_constructor_factory_to_generic() async {
@@ -3352,13 +4142,8 @@
     var nullable_i1 = decoratedTypeAnnotation('int/*1*/').node;
     var nullable_i2 = decoratedTypeAnnotation('int/*2*/').node;
     var nullable_t3 = decoratedTypeAnnotation('T/*3*/').node;
-    var nullable_i2_or_nullable_t3 = graph
-        .getDownstreamEdges(nullable_i1)
-        .single
-        .destinationNode as NullabilityNodeForSubstitution;
-    expect(nullable_i2_or_nullable_t3.innerNode, same(nullable_i2));
-    expect(nullable_i2_or_nullable_t3.outerNode, same(nullable_t3));
-    assertEdge(nullable_i1, nullable_i2_or_nullable_t3, hard: true);
+    assertEdge(nullable_i1, substitutionNode(nullable_i2, nullable_t3),
+        hard: true);
   }
 
   test_redirecting_constructor_ordinary() async {
@@ -3457,60 +4242,74 @@
         checkExpression('null'), assertEdge(always, tNode, hard: false));
   }
 
-  @failingTest
   test_setOrMapLiteral_map_noTypeArgument_noNullableKeysAndValues() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Map<String, int> f() {
   return {'a' : 1, 'b' : 2};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
-    // TODO(brianwilkerson) Add an assertion that there is an edge from the set
-    //  literal's fake type argument to the return type's type argument.
+    var keyNode = decoratedTypeAnnotation('String').node;
+    var valueNode = decoratedTypeAnnotation('int').node;
+    var mapNode = decoratedTypeAnnotation('Map').node;
+
+    assertNoUpstreamNullability(mapNode);
+    assertNoUpstreamNullability(
+        assertEdge(anyNode, keyNode, hard: false).primarySource);
+    assertNoUpstreamNullability(
+        assertEdge(anyNode, valueNode, hard: false).primarySource);
   }
 
-  @failingTest
   test_setOrMapLiteral_map_noTypeArgument_nullableKey() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Map<String, int> f() {
   return {'a' : 1, null : 2, 'c' : 3};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
-    assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
-    assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
+    var keyNode = decoratedTypeAnnotation('String').node;
+    var valueNode = decoratedTypeAnnotation('int').node;
+    var mapNode = decoratedTypeAnnotation('Map').node;
+
+    assertNoUpstreamNullability(mapNode);
+    assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
+        hard: false);
+    assertNoUpstreamNullability(
+        assertEdge(anyNode, valueNode, hard: false).primarySource);
   }
 
-  @failingTest
   test_setOrMapLiteral_map_noTypeArgument_nullableKeyAndValue() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Map<String, int> f() {
   return {'a' : 1, null : null, 'c' : 3};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
-    assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
-    assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
+    var keyNode = decoratedTypeAnnotation('String').node;
+    var valueNode = decoratedTypeAnnotation('int').node;
+    var mapNode = decoratedTypeAnnotation('Map').node;
+
+    assertNoUpstreamNullability(mapNode);
+    assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
+        hard: false);
+    assertEdge(
+        always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+        hard: false);
   }
 
-  @failingTest
   test_setOrMapLiteral_map_noTypeArgument_nullableValue() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Map<String, int> f() {
   return {'a' : 1, 'b' : null, 'c' : 3};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
-    assertNoUpstreamNullability(decoratedTypeAnnotation('String').node);
-    assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
+    var keyNode = decoratedTypeAnnotation('String').node;
+    var valueNode = decoratedTypeAnnotation('int').node;
+    var mapNode = decoratedTypeAnnotation('Map').node;
+
+    assertNoUpstreamNullability(mapNode);
+    assertNoUpstreamNullability(
+        assertEdge(anyNode, keyNode, hard: false).primarySource);
+    assertEdge(
+        always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+        hard: false);
   }
 
   test_setOrMapLiteral_map_typeArguments_noNullableKeysAndValues() async {
@@ -3567,31 +4366,33 @@
     assertEdge(always, decoratedTypeAnnotation('int>{').node, hard: false);
   }
 
-  @failingTest
   test_setOrMapLiteral_set_noTypeArgument_noNullableElements() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Set<String> f() {
   return {'a', 'b'};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
-    // TODO(brianwilkerson) Add an assertion that there is an edge from the set
-    //  literal's fake type argument to the return type's type argument.
+    var valueNode = decoratedTypeAnnotation('String').node;
+    var setNode = decoratedTypeAnnotation('Set').node;
+
+    assertNoUpstreamNullability(setNode);
+    assertNoUpstreamNullability(
+        assertEdge(anyNode, valueNode, hard: false).primarySource);
   }
 
-  @failingTest
   test_setOrMapLiteral_set_noTypeArgument_nullableElement() async {
-    // Failing because we're not yet handling collection literals without a
-    // type argument.
     await analyze('''
 Set<String> f() {
   return {'a', null, 'c'};
 }
 ''');
-    assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
-    assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
+    var valueNode = decoratedTypeAnnotation('String').node;
+    var setNode = decoratedTypeAnnotation('Set').node;
+
+    assertNoUpstreamNullability(setNode);
+    assertEdge(
+        always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+        hard: false);
   }
 
   test_setOrMapLiteral_set_typeArgument_noNullableElements() async {
@@ -3691,6 +4492,103 @@
     assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
   }
 
+  test_spread_element_list() async {
+    await analyze('''
+void f(List<int> ints) {
+  <int>[...ints];
+}
+''');
+
+    assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
+    assertEdge(
+        substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+  }
+
+  test_spread_element_list_dynamic() async {
+    await analyze('''
+void f(dynamic ints) {
+  <int>[...ints];
+}
+''');
+
+    // Mostly just check this doesn't crash.
+    assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: true);
+  }
+
+  test_spread_element_list_nullable() async {
+    await analyze('''
+void f(List<int> ints) {
+  <int>[...?ints];
+}
+''');
+
+    assertNoEdge(decoratedTypeAnnotation('List<int>').node, never);
+    assertEdge(
+        substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+  }
+
+  test_spread_element_map() async {
+    await analyze('''
+void f(Map<String, int> map) {
+  <String, int>{...map};
+}
+''');
+
+    assertEdge(decoratedTypeAnnotation('Map<String, int>').node, never,
+        hard: true);
+    assertEdge(decoratedTypeAnnotation('String, int> map').node,
+        decoratedTypeAnnotation('String, int>{').node,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('int> map').node,
+        decoratedTypeAnnotation('int>{').node,
+        hard: false);
+  }
+
+  test_spread_element_set() async {
+    await analyze('''
+void f(Set<int> ints) {
+  <int>{...ints};
+}
+''');
+
+    assertEdge(decoratedTypeAnnotation('Set<int>').node, never, hard: true);
+    assertEdge(
+        substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+        decoratedTypeAnnotation('int>{').node,
+        hard: false);
+  }
+
+  test_spread_element_subtype() async {
+    await analyze('''
+abstract class C<T, R> implements Iterable<R> {}
+void f(C<dynamic, int> ints) {
+  <int>[...ints];
+}
+''');
+
+    assertEdge(decoratedTypeAnnotation('C<dynamic, int>').node, never,
+        hard: true);
+    assertEdge(
+        substitutionNode(decoratedTypeAnnotation('int> ints').node,
+            decoratedTypeAnnotation('R> {}').node),
+        decoratedTypeAnnotation('int>[').node,
+        hard: false);
+  }
+
+  test_static_method_call_prefixed() async {
+    await analyze('''
+import 'dart:async' as a;
+void f(void Function() callback) {
+  a.Timer.run(callback);
+}
+''');
+    // No assertions.  Just making sure this doesn't crash.
+  }
+
   test_stringLiteral() async {
     // TODO(paulberry): also test string interpolations
     await analyze('''
@@ -3837,7 +4735,15 @@
         hard: true);
   }
 
-  test_typeName() async {
+  test_typeName_class() async {
+    await analyze('''
+class C {}
+Type f() => C;
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+  }
+
+  test_typeName_from_sdk() async {
     await analyze('''
 Type f() {
   return int;
@@ -3846,6 +4752,38 @@
     assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
   }
 
+  test_typeName_from_sdk_prefixed() async {
+    await analyze('''
+import 'dart:async' as a;
+Type f() => a.Future;
+''');
+    assertEdge(never, decoratedTypeAnnotation('Type').node, hard: false);
+  }
+
+  test_typeName_functionTypeAlias() async {
+    await analyze('''
+typedef void F();
+Type f() => F;
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+  }
+
+  test_typeName_genericTypeAlias() async {
+    await analyze('''
+typedef F = void Function();
+Type f() => F;
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+  }
+
+  test_typeName_mixin() async {
+    await analyze('''
+mixin M {}
+Type f() => M;
+''');
+    assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+  }
+
   test_typeName_union_with_bound() async {
     await analyze('''
 class C<T extends Object> {}
@@ -3905,6 +4843,11 @@
       return assignmentCheckerTest._myListOfListSupertype
           .substitute({class_.typeParameters[0]: type.typeArguments[0]});
     }
+    if (class_.name == 'Future' && superclass.name == 'FutureOr') {
+      return DecoratedType(
+          superclass.type.instantiate([type.typeArguments[0].type]), type.node,
+          typeArguments: [type.typeArguments[0]]);
+    }
     throw UnimplementedError(
         'TODO(paulberry): asInstanceOf($type, $superclass)');
   }
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index bf9d88c..f335eb45 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -21,6 +21,19 @@
 
 import 'abstract_single_unit.dart';
 
+/// A [NodeMatcher] that matches any node, and records what node it matched to.
+class AnyNodeMatcher implements NodeMatcher {
+  final List<NullabilityNode> _matchingNodes = [];
+
+  NullabilityNode get matchingNode => _matchingNodes.single;
+
+  @override
+  bool matches(NullabilityNode node) {
+    _matchingNodes.add(node);
+    return true;
+  }
+}
+
 /// Mixin allowing unit tests to create decorated types easily.
 mixin DecoratedTypeTester implements DecoratedTypeTesterBase {
   int _offset = 0;
@@ -66,6 +79,19 @@
         namedParameters: named);
   }
 
+  DecoratedType future(DecoratedType parameter, {NullabilityNode node}) {
+    return DecoratedType(typeProvider.futureType.instantiate([parameter.type]),
+        node ?? newNode(),
+        typeArguments: [parameter]);
+  }
+
+  DecoratedType futureOr(DecoratedType parameter, {NullabilityNode node}) {
+    return DecoratedType(
+        typeProvider.futureOrType.instantiate([parameter.type]),
+        node ?? newNode(),
+        typeArguments: [parameter]);
+  }
+
   DecoratedType int_({NullabilityNode node}) =>
       DecoratedType(typeProvider.intType, node ?? newNode());
 
@@ -99,12 +125,32 @@
   TypeProvider get typeProvider;
 }
 
+class EdgeBuilderTestBase extends MigrationVisitorTestBase {
+  /// Analyzes the given source code, producing constraint variables and
+  /// constraints for it.
+  @override
+  Future<CompilationUnit> analyze(String code) async {
+    var unit = await super.analyze(code);
+    unit.accept(EdgeBuilder(
+        typeProvider, typeSystem, variables, graph, testSource, null));
+    return unit;
+  }
+}
+
 /// Mixin allowing unit tests to check for the presence of graph edges.
 mixin EdgeTester {
+  /// Returns a [NodeMatcher] that matches any node whatsoever.
+  AnyNodeMatcher get anyNode => AnyNodeMatcher();
+
   NullabilityGraphForTesting get graph;
 
-  NullabilityEdge assertEdge(
-      NullabilityNode source, NullabilityNode destination,
+  /// Asserts that an edge exists with a node matching [source] and a node
+  /// matching [destination], and with the given [hard]ness and [guards].
+  ///
+  /// [source] and [destination] are converted to [NodeMatcher] objects if they
+  /// aren't already.  In practice this means that the caller can pass in either
+  //  /// a [NodeMatcher] or a [NullabilityNode].
+  NullabilityEdge assertEdge(Object source, Object destination,
       {@required bool hard, List<NullabilityNode> guards = const []}) {
     var edges = getEdges(source, destination);
     if (edges.length == 0) {
@@ -119,14 +165,25 @@
     }
   }
 
-  void assertNoEdge(NullabilityNode source, NullabilityNode destination) {
+  /// Asserts that no edge exists with a node matching [source] and a node
+  /// matching [destination].
+  ///
+  /// [source] and [destination] are converted to [NodeMatcher] objects if they
+  /// aren't already.  In practice this means that the caller can pass in either
+  /// a [NodeMatcher] or a [NullabilityNode].
+  void assertNoEdge(Object source, Object destination) {
     var edges = getEdges(source, destination);
     if (edges.isNotEmpty) {
       fail('Expected no edge $source -> $destination, found ${edges.length}');
     }
   }
 
-  void assertUnion(NullabilityNode x, NullabilityNode y) {
+  /// Asserts that a union-type edge exists between nodes [x] and [y].
+  ///
+  /// [x] and [y] are converted to [NodeMatcher] objects if they aren't already.
+  /// In practice this means that the caller can pass in either a [NodeMatcher]
+  /// or a [NullabilityNode].
+  void assertUnion(Object x, Object y) {
     var edges = getEdges(x, y);
     for (var edge in edges) {
       if (edge.isUnion) {
@@ -137,12 +194,31 @@
     fail('Expected union between $x and $y, not found');
   }
 
-  List<NullabilityEdge> getEdges(
-          NullabilityNode source, NullabilityNode destination) =>
-      graph
-          .getUpstreamEdges(destination)
-          .where((e) => e.primarySource == source)
-          .toList();
+  /// Gets a list of all edges whose source matches [source] and whose
+  /// destination matches [destination].
+  ///
+  /// [source] and [destination] are converted to [NodeMatcher] objects if they
+  /// aren't already.  In practice this means that the caller can pass in either
+  /// a [NodeMatcher] or a [NullabilityNode].
+  List<NullabilityEdge> getEdges(Object source, Object destination) {
+    var sourceMatcher = NodeMatcher(source);
+    var destinationMatcher = NodeMatcher(destination);
+    return graph
+        .getAllEdges()
+        .where((e) =>
+            sourceMatcher.matches(e.primarySource) &&
+            destinationMatcher.matches(e.destinationNode))
+        .toList();
+  }
+
+  /// Creates a [NodeMatcher] matching a substitution node whose inner and outer
+  /// nodes match [inner] and [outer].
+  ///
+  /// [inner] and [outer] are converted to [NodeMatcher] objects if they aren't
+  /// already.  In practice this means that the caller can pass in either a
+  /// [NodeMatcher] or a [NullabilityNode].
+  NodeMatcher substitutionNode(Object inner, Object outer) =>
+      _SubstitutionNodeMatcher(NodeMatcher(inner), NodeMatcher(outer));
 }
 
 /// Mock representation of constraint variables.
@@ -155,7 +231,8 @@
 
   final _possiblyOptional = <DefaultFormalParameter, NullabilityNode>{};
 
-  InstrumentedVariables(NullabilityGraph graph) : super(graph);
+  InstrumentedVariables(NullabilityGraph graph, TypeProvider typeProvider)
+      : super(graph, typeProvider);
 
   /// Gets the [ExpressionChecks] associated with the given [expression].
   ExpressionChecks checkExpression(Expression expression) =>
@@ -209,27 +286,14 @@
   }
 }
 
-class EdgeBuilderTestBase extends MigrationVisitorTestBase {
-  /// Analyzes the given source code, producing constraint variables and
-  /// constraints for it.
-  @override
-  Future<CompilationUnit> analyze(String code) async {
-    var unit = await super.analyze(code);
-    unit.accept(EdgeBuilder(
-        typeProvider, typeSystem, variables, graph, testSource, null));
-    return unit;
-  }
-}
-
 class MigrationVisitorTestBase extends AbstractSingleUnitTest with EdgeTester {
-  final InstrumentedVariables variables;
+  InstrumentedVariables variables;
 
   final NullabilityGraphForTesting graph;
 
   MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());
 
-  MigrationVisitorTestBase._(this.graph)
-      : variables = InstrumentedVariables(graph);
+  MigrationVisitorTestBase._(this.graph);
 
   NullabilityNode get always => graph.always;
 
@@ -241,6 +305,7 @@
 
   Future<CompilationUnit> analyze(String code) async {
     await resolveTestUnit(code);
+    variables = InstrumentedVariables(graph, typeProvider);
     testUnit
         .accept(NodeBuilder(variables, testSource, null, graph, typeProvider));
     return testUnit;
@@ -284,3 +349,42 @@
     return variables.conditionalDiscard(findNode.statement(text));
   }
 }
+
+/// Abstract base class representing a thing that can be matched against
+/// nullability nodes.
+abstract class NodeMatcher {
+  factory NodeMatcher(Object expectation) {
+    if (expectation is NodeMatcher) return expectation;
+    if (expectation is NullabilityNode) return _ExactNodeMatcher(expectation);
+    fail(
+        'Unclear how to match node expectation of type ${expectation.runtimeType}');
+  }
+
+  bool matches(NullabilityNode node);
+}
+
+/// A [NodeMatcher] that matches exactly one node.
+class _ExactNodeMatcher implements NodeMatcher {
+  final NullabilityNode _expectation;
+
+  _ExactNodeMatcher(this._expectation);
+
+  @override
+  bool matches(NullabilityNode node) => node == _expectation;
+}
+
+/// A [NodeMatcher] that matches a substitution node with the given inner and
+/// outer nodes.
+class _SubstitutionNodeMatcher implements NodeMatcher {
+  final NodeMatcher inner;
+  final NodeMatcher outer;
+
+  _SubstitutionNodeMatcher(this.inner, this.outer);
+
+  @override
+  bool matches(NullabilityNode node) {
+    return node is NullabilityNodeForSubstitution &&
+        inner.matches(node.innerNode) &&
+        outer.matches(node.outerNode);
+  }
+}
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index 70c0fdbb..a85aed0 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -28,6 +28,66 @@
       variables.decoratedTypeParameterBound(
           findNode.typeParameter(search).declaredElement);
 
+  test_catch_clause_with_stacktrace_with_on() async {
+    await analyze('''
+void f() {
+  try {} on String catch (ex, st) {}
+}
+''');
+    var exceptionType =
+        variables.decoratedElementType(findNode.simple('ex').staticElement);
+    expect(exceptionType.node, TypeMatcher<NullabilityNodeMutable>());
+    var stackTraceType =
+        variables.decoratedElementType(findNode.simple('st').staticElement);
+    expect(stackTraceType.node, never);
+  }
+
+  test_catch_clause_with_stacktrace_without_on() async {
+    await analyze('''
+void f() {
+  try {} catch (ex, st) {}
+}
+''');
+    var exceptionType =
+        variables.decoratedElementType(findNode.simple('ex').staticElement);
+    expect(exceptionType.node, always);
+    var stackTraceType =
+        variables.decoratedElementType(findNode.simple('st').staticElement);
+    expect(stackTraceType.node, never);
+  }
+
+  test_catch_clause_without_catch() async {
+    await analyze('''
+void f() {
+  try {} on String {}
+}
+''');
+    // No assertions, since no variables are declared; we just want to make sure
+    // we don't crash.
+  }
+
+  test_catch_clause_without_stacktrace_with_on() async {
+    await analyze('''
+void f() {
+  try {} on String catch (ex) {}
+}
+''');
+    var exceptionType =
+        variables.decoratedElementType(findNode.simple('ex').staticElement);
+    expect(exceptionType.node, TypeMatcher<NullabilityNodeMutable>());
+  }
+
+  test_catch_clause_without_stacktrace_without_on() async {
+    await analyze('''
+void f() {
+  try {} catch (ex) {}
+}
+''');
+    var exceptionType =
+        variables.decoratedElementType(findNode.simple('ex').staticElement);
+    expect(exceptionType.node, always);
+  }
+
   test_class_alias_synthetic_constructors_no_parameters() async {
     await analyze('''
 class C {
@@ -338,6 +398,19 @@
         same(decoratedTypeAnnotation('V>;').node));
   }
 
+  test_directSupertypes_dartCoreClass() async {
+    await analyze('''
+abstract class D<V> extends Iterable<V> {}
+''');
+    var types = decoratedDirectSupertypes('D');
+    var super_ = types.values.single;
+    expect(super_.type.toString(), 'Iterable<V>');
+    expect(super_.node, same(never));
+    expect(super_.typeArguments, hasLength(1));
+    expect(super_.typeArguments[0].node,
+        same(decoratedTypeAnnotation('V> {').node));
+  }
+
   test_directSupertypes_mixin_extends_default() async {
     await analyze('''
 mixin C<T, U> {}
@@ -1459,6 +1532,80 @@
     expect(bound.type, same(typeProvider.objectType));
   }
 
+  test_typedef_reference_generic_instantiated() async {
+    await analyze('''
+typedef F<T> = T Function();
+F<int> f;
+''');
+    // The instantiation of F should produce fresh nullability nodes, distinct
+    // from the ones in the typedef (they will be unified by the edge builder).
+    // This is necessary because there is no guarantee of whether the typedef or
+    // its usage will be visited first.
+    var typedefDecoratedType =
+        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+    var decoratedType = decoratedTypeAnnotation('F<int>');
+    expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+    expect(decoratedType.returnType.type.toString(), 'int');
+    expect(
+        decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.returnType.node,
+        isNot(same(typedefDecoratedType.returnType.node)));
+    expect(decoratedType.typeFormalBounds, isEmpty);
+  }
+
+  test_typedef_reference_generic_uninstantiated() async {
+    await analyze('''
+typedef F = T Function<T extends num>();
+F f;
+''');
+    // The instantiation of F should produce fresh nullability nodes, distinct
+    // from the ones in the typedef (they will be unified by the edge builder).
+    // This is necessary because there is no guarantee of whether the typedef or
+    // its usage will be visited first.
+    var typedefDecoratedType =
+        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+    var decoratedType = decoratedTypeAnnotation('F f');
+    expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+    expect(decoratedType.returnType.type.toString(), 'T');
+    expect(
+        decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.returnType.node,
+        isNot(same(typedefDecoratedType.returnType.node)));
+    expect(decoratedType.typeFormalBounds, hasLength(1));
+    expect(decoratedType.typeFormalBounds[0].type.toString(), 'num');
+    expect(decoratedType.typeFormalBounds[0].node,
+        isNot(same(typedefDecoratedType.typeFormalBounds[0].node)));
+  }
+
+  test_typedef_reference_simple() async {
+    await analyze('''
+typedef int F(String s);
+F f;
+''');
+    // The instantiation of F should produce fresh nullability nodes, distinct
+    // from the ones in the typedef (they will be unified by the edge builder).
+    // This is necessary because there is no guarantee of whether the typedef or
+    // its usage will be visited first.
+    var typedefDecoratedType =
+        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+    var decoratedType = decoratedTypeAnnotation('F f');
+    expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+    expect(decoratedType.returnType.type.toString(), 'int');
+    expect(
+        decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.returnType.node,
+        isNot(same(typedefDecoratedType.returnType.node)));
+    expect(decoratedType.positionalParameters[0].type.toString(), 'String');
+    expect(decoratedType.positionalParameters[0].node,
+        TypeMatcher<NullabilityNodeMutable>());
+    expect(decoratedType.positionalParameters[0].node,
+        isNot(same(typedefDecoratedType.positionalParameters[0].node)));
+    expect(decoratedType.typeFormalBounds, isEmpty);
+  }
+
   test_variableDeclaration_type_simple() async {
     await analyze('''
 main() {
diff --git a/pkg/nnbd_migration/tool/trial_migration.dart b/pkg/nnbd_migration/tool/trial_migration.dart
index 3bb8f85..f207d07 100644
--- a/pkg/nnbd_migration/tool/trial_migration.dart
+++ b/pkg/nnbd_migration/tool/trial_migration.dart
@@ -45,6 +45,7 @@
         .where((s) => s.endsWith('.dart'))
         .toList();
     print('  ${files.length} files found');
+    var previousExceptionCount = listener.numExceptions;
     var migration = NullabilityMigration(listener, permissive: true);
     for (var file in files) {
       var resolvedUnit = await context.currentSession.getResolvedUnit(file);
@@ -55,6 +56,8 @@
       migration.processInput(resolvedUnit);
     }
     migration.finish();
+    var exceptionCount = listener.numExceptions - previousExceptionCount;
+    print('  $exceptionCount exceptions in this package');
   }
   print('${listener.numTypesMadeNullable} types made nullable');
   print('${listener.numNullChecksAdded} null checks added');
@@ -75,6 +78,11 @@
 /// if its category contains the string.
 const String categoryOfInterest = null;
 
+/// Set this to `true` to cause just the exception nodes to be printed when
+/// `categoryOfInterest` is non-null.  Set this to `false` to cause the full
+/// stack trace to be printed.
+const bool printExceptionNodeOnly = false;
+
 class _Listener implements NullabilityMigrationListener {
   final groupedExceptions = <String, List<String>>{};
 
@@ -128,7 +136,11 @@
 $stackTrace
 ''';
     if (categoryOfInterest != null && category.contains(categoryOfInterest)) {
-      print(detail);
+      if (printExceptionNodeOnly) {
+        print('$node');
+      } else {
+        print(detail);
+      }
     }
     (groupedExceptions[category] ??= []).add(detail);
     ++numExceptions;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index cee0e7a..47913ba 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -39,7 +39,10 @@
 front_end/test/fasta/rasta/*: SkipByDesign # Anything in rasta is input to fasta unit tests and shouldn't be run as tests.
 front_end/test/fasta/sdk_test: SkipByDesign # sdk_test would take too long to complete, and should be run in a different way.
 front_end/test/fasta/shaker_test: Skip # Issue http://dartbug.com/32531
-front_end/test/fasta/strong_test: Pass, ExtraSlow
+front_end/test/fasta/strong1_test: Pass, ExtraSlow
+front_end/test/fasta/strong2_test: Pass, ExtraSlow
+front_end/test/fasta/strong3_test: Pass, ExtraSlow
+front_end/test/fasta/strong4_test: Pass, ExtraSlow
 front_end/test/fasta/text_serialization_test: Pass, ExtraSlow
 front_end/test/fasta/types/dart2js_benchmark_test: Pass, Slow
 front_end/test/fasta/types/large_app_benchmark_test: Pass, ExtraSlow
@@ -47,7 +50,7 @@
 front_end/test/whole_program_test: Slow, Pass
 front_end/testcases/*: Skip # These are not tests but input for tests.
 front_end/tool/incremental_perf_test: Slow, Pass
-kernel/test/closures_test: Slow, Pass
+kernel/test/closures_test: Slow
 kernel/testcases/*: Skip # These are not tests but input for tests.
 vm/test/frontend_server_test: Slow
 vm/test/transformations/type_flow/transformer_test: Slow
@@ -68,12 +71,6 @@
 analyzer_plugin/test/*: SkipByDesign # Only meant to run on vm
 analyzer_plugin/tool/*: SkipByDesign # Only meant to run on vm
 build_integration/test/*: SkipByDesign # Only meant to run on vm, most use dart:mirrors and dart:io
-collection/test/equality_test/01: Fail # Issue 1533
-collection/test/equality_test/02: Fail # Issue 1533
-collection/test/equality_test/03: Fail # Issue 1533
-collection/test/equality_test/04: Fail # Issue 1533
-collection/test/equality_test/05: Fail # Issue 1533
-collection/test/equality_test/none: Pass, Fail # Issue 14348
 compiler/tool/*: SkipByDesign # Only meant to run on vm
 dartfix/test/*: SkipByDesign # Only meant to run on vm
 front_end/test/*: SkipByDesign # Only meant to run on vm, most use dart:mirrors and dart:io
@@ -86,23 +83,15 @@
 telemetry/test/*: SkipByDesign # Only meant to run on vm
 test_runner/test/*: SkipByDesign # Only meant to run on vm
 testing/*: SkipByDesign # Only meant to run on vm
-typed_data/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
 
 [ $runtime == dart_precompiled ]
 *: SkipByDesign # The pkg test framework imports dart:mirrors.
 
-[ $runtime == jsshell ]
-async/test/stream_zip_test: RuntimeError, OK # Issue 26103. Timers are not supported.
-front_end/test/*: RuntimeError, OK, Pass # Issue 26103. Timers are not supported.
-kernel/test/*: RuntimeError, OK # Issue 26103. Timers are not supported.
-
 [ $runtime == vm ]
 analysis_server/test/benchmarks_test: Slow
 analysis_server/test/domain_completion_test: Slow
 analysis_server/test/edit/refactoring_test: Slow
 analysis_server/test/integration/*: Slow
-analysis_server/test/integration/analysis/package_root_test: Pass, RuntimeError # Issue 33382
-analysis_server/test/integration/search/find_top_level_declarations_test: Pass, RuntimeError # 31571
 analysis_server/test/services/completion/dart/imported_reference_contributor_test: Slow
 analysis_server/test/services/completion/dart/keyword_contributor_test: Slow
 analysis_server/test/services/completion/dart/local_constructor_contributor_test: Slow
@@ -113,7 +102,6 @@
 analysis_server/test/services/refactoring/inline_method_test: Slow
 analysis_server/test/socket_server_test: Skip # Pass, Slow
 analysis_server/test/src/plugin/plugin_manager_test: Slow
-analyzer/test/file_system/physical_resource_provider_watch_test: Pass, Fail # Issue 25472
 analyzer/test/generated/hint_code_driver_test: Slow
 analyzer/test/generated/non_error_resolver_kernel_test: Slow
 analyzer/test/generated/strong_mode_driver_test: Slow
@@ -124,16 +112,13 @@
 analyzer/test/src/task/strong/inferred_type_test: Slow
 analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test: Slow
 analyzer_plugin/test/src/utilities/completion/optype_test: Slow
-dartfix/test/src/driver_test: RuntimeError # dartbug.com/35478
 mutation_observer: Skip # Skip tests on the VM if the package depends on dart:html
 
 [ $runtime != vm ]
 dev_compiler/test/options/*: SkipByDesign
 front_end/test/hot_reload_e2e_test: Skip
 vm/test/*: SkipByDesign # Only meant to run on vm
-
-[ $system == linux ]
-analysis_server/test/integration/analysis/package_root_test: Pass, RuntimeError # Issue 33382
+vm_service/test/*: SkipByDesign # Uses dart:io
 
 [ $system == windows ]
 analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test: Skip
@@ -154,9 +139,7 @@
 analyzer_cli/*: SkipByDesign # Uses dart:io.
 compiler/tool/*: SkipByDesign # Only meant to run on vm
 front_end/tool/*: SkipByDesign # Only meant to run on vm
-http_server/test/*: Fail, OK # Uses dart:io.
 kernel/test/*: SkipByDesign # Uses dart:io and bigints.
-observe/test/transformer_test: Fail, OK # Uses dart:io.
 observe/test/unique_message_test: SkipByDesign # Uses dart:io.
 status_file/*: SkipByDesign # Only meant to run on the standalone VM.
 testing/test/analyze_test: SkipByDesign
@@ -164,10 +147,6 @@
 [ $jscl ]
 kernel/test/*: SkipByDesign # Uses dart:io and bigints.
 
-[ !$preview_dart_2 ]
-dev_compiler/*: SkipByDesign # uses Dart 2.
-smith/test/*: Skip # Uses optional new.
-
 [ $arch == x64 && $runtime == vm && $system == windows && $checked ]
 analyzer/test/src/task/strong/inferred_type_test: Slow
 
@@ -185,7 +164,7 @@
 modular_test/test/src/find_sdk_root2_test: SkipByDesign
 
 [ $compiler == dart2js && $runtime == chrome && $system == macos ]
-third_party/di_tests/di_test: Pass, Slow # Issue 22896
+third_party/di_tests/di_test: Slow # Issue 22896
 
 [ $compiler == dart2js && $runtime == d8 ]
 front_end/test/src/base/uri_resolver_test: SkipByDesign # Relies on access to file system
@@ -209,9 +188,7 @@
 
 [ $runtime == vm && $system == windows ]
 analysis_server/test/analysis/get_errors_test: Skip # runtime error, Issue 22180
-analysis_server/test/benchmarks_test: RuntimeError # Issue 32355
-analysis_server/test/src/plugin/plugin_manager_test: Pass, Slow, RuntimeError # Issue 34231
-analyzer/test/generated/non_error_resolver_kernel_test: RuntimeError # Issue 30785
+analysis_server/test/src/plugin/plugin_manager_test: Slow # Issue 34231
 analyzer/test/src/task/strong/checker_test: Slow
 analyzer/tool/task_dependency_graph/check_test: Slow
 
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index eb79e61..fc7883a 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -3,14 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 import 'dart:io';
 
-// TODO(rnystrom): Differences from test.dart's version:
-// - Remove special handling for "ff" as firefox.
-// - "windows" -> "win".
-// - "macos" -> "mac".
-// - toString() on enum classes is just name.
-// - builderTag and babel default to empty string, not null.
-// Need to migrate test.dart to not expect the above before it can use this.
-
 // READ ME! If you add a new field to this, make sure to add it to
 // [parse()], [optionsEqual()], [hashCode], and [toString()]. A good check is to
 // comment out an existing field and see what breaks. Every error is a place
@@ -123,7 +115,7 @@
 
     // Infer option values from the words in the configuration name.
     var words = name.split("-").toSet();
-    var optionsCopy = new Map.of(optionsJson);
+    var optionsCopy = Map.of(optionsJson);
 
     T enumOption<T extends NamedEnum>(
         String option, List<String> allowed, T Function(String) parse) {
@@ -210,7 +202,7 @@
         throw FormatException('Option "$option" had value "$value", which is '
             'not a List.');
       }
-      return new List<String>.from(value as List);
+      return List<String>.from(value as List);
     }
 
     // Extract options from the name and map.
@@ -220,10 +212,12 @@
     var mode = enumOption("mode", Mode.names, Mode.find);
     var runtime = enumOption("runtime", Runtime.names, Runtime.find);
     var system = enumOption("system", System.names, System.find);
+    var nnbdMode = enumOption("nnbd", NnbdMode.names, NnbdMode.find);
 
     // Fill in any missing values using defaults when possible.
     architecture ??= Architecture.x64;
     system ??= System.host;
+    nnbdMode ??= NnbdMode.legacy;
 
     // Infer from compiler from runtime or vice versa.
     if (compiler == null) {
@@ -247,17 +241,18 @@
 
     var configuration = Configuration(
         name, architecture, compiler, mode, runtime, system,
+        nnbdMode: nnbdMode,
         babel: stringOption("babel"),
         builderTag: stringOption("builder-tag"),
         vmOptions: stringListOption("vm-options"),
         dart2jsOptions: stringListOption("dart2js-options"),
+        experiments: stringListOption("experiments"),
         timeout: intOption("timeout"),
         enableAsserts: boolOption("enable-asserts"),
         isChecked: boolOption("checked"),
         isCsp: boolOption("csp"),
         isHostChecked: boolOption("host-checked"),
         isMinified: boolOption("minified"),
-        previewDart2: boolOption("preview-dart-2"),
         useAnalyzerCfe: boolOption("use-cfe"),
         useAnalyzerFastaParser: boolOption("analyzer-use-fasta-parser"),
         useBlobs: boolOption("use-blobs"),
@@ -268,7 +263,7 @@
 
     // Should have consumed the whole map.
     if (optionsCopy.isNotEmpty) {
-      throw new FormatException('Unknown option "${optionsCopy.keys.first}".');
+      throw FormatException('Unknown option "${optionsCopy.keys.first}".');
     }
 
     return configuration;
@@ -286,6 +281,9 @@
 
   final System system;
 
+  /// Which NNBD mode to run the test files under.
+  final NnbdMode nnbdMode;
+
   final String babel;
 
   final String builderTag;
@@ -294,6 +292,17 @@
 
   final List<String> dart2jsOptions;
 
+  /// The names of the experiments to enable while running tests.
+  ///
+  /// A test may *require* an experiment to always be enabled by containing a
+  /// comment like:
+  ///
+  ///     // SharedOptions=--enable-experiment=extension-methods
+  ///
+  /// Enabling an experiment here in the configuration allows running the same
+  /// test both with an experiment on and off.
+  final List<String> experiments;
+
   final int timeout;
 
   final bool enableAsserts;
@@ -308,9 +317,6 @@
 
   final bool isMinified;
 
-  // TODO(rnystrom): Remove this when Dart 1.0 is no longer supported.
-  final bool previewDart2;
-
   // TODO(whesse): Remove these when only fasta front end is in analyzer.
   final bool useAnalyzerCfe;
   final bool useAnalyzerFastaParser;
@@ -326,17 +332,18 @@
 
   Configuration(this.name, this.architecture, this.compiler, this.mode,
       this.runtime, this.system,
-      {String babel,
+      {NnbdMode nnbdMode,
+      String babel,
       String builderTag,
       List<String> vmOptions,
       List<String> dart2jsOptions,
+      List<String> experiments,
       int timeout,
       bool enableAsserts,
       bool isChecked,
       bool isCsp,
       bool isHostChecked,
       bool isMinified,
-      bool previewDart2,
       bool useAnalyzerCfe,
       bool useAnalyzerFastaParser,
       bool useBlobs,
@@ -344,17 +351,18 @@
       bool useHotReload,
       bool useHotReloadRollback,
       bool useSdk})
-      : babel = babel ?? "",
+      : nnbdMode = nnbdMode ?? NnbdMode.legacy,
+        babel = babel ?? "",
         builderTag = builderTag ?? "",
         vmOptions = vmOptions ?? <String>[],
         dart2jsOptions = dart2jsOptions ?? <String>[],
+        experiments = experiments ?? <String>[],
         timeout = timeout ?? -1,
         enableAsserts = enableAsserts ?? false,
         isChecked = isChecked ?? false,
         isCsp = isCsp ?? false,
         isHostChecked = isHostChecked ?? false,
         isMinified = isMinified ?? false,
-        previewDart2 = previewDart2 ?? true,
         useAnalyzerCfe = useAnalyzerCfe ?? false,
         useAnalyzerFastaParser = useAnalyzerFastaParser ?? false,
         useBlobs = useBlobs ?? false,
@@ -371,17 +379,18 @@
       mode == other.mode &&
       runtime == other.runtime &&
       system == other.system &&
+      nnbdMode == other.nnbdMode &&
       babel == other.babel &&
       builderTag == other.builderTag &&
-      vmOptions.join(" & ") == other.vmOptions.join(" & ") &&
-      dart2jsOptions.join(" & ") == other.dart2jsOptions.join(" & ") &&
+      _listsEqual(vmOptions, other.vmOptions) &&
+      _listsEqual(dart2jsOptions, other.dart2jsOptions) &&
+      _listsEqual(experiments, other.experiments) &&
       timeout == other.timeout &&
       enableAsserts == other.enableAsserts &&
       isChecked == other.isChecked &&
       isCsp == other.isCsp &&
       isHostChecked == other.isHostChecked &&
       isMinified == other.isMinified &&
-      previewDart2 == other.previewDart2 &&
       useAnalyzerCfe == other.useAnalyzerCfe &&
       useAnalyzerFastaParser == other.useAnalyzerFastaParser &&
       useBlobs == other.useBlobs &&
@@ -390,6 +399,20 @@
       useHotReloadRollback == other.useHotReloadRollback &&
       useSdk == other.useSdk;
 
+  /// Whether [a] and [b] contain the same strings, regardless of order.
+  bool _listsEqual(List<String> a, List<String> b) {
+    if (a.length != b.length) return false;
+
+    // Using sorted lists instead of sets in case there are duplicate strings
+    // in the lists. ["a"] should not be considered equal to ["a", "a"].
+    var aSorted = a.toList()..sort();
+    var bSorted = b.toList()..sort();
+    for (var i = 0; i < aSorted.length; i++) {
+      if (aSorted[i] != bSorted[i]) return false;
+    }
+    return true;
+  }
+
   bool operator ==(Object other) =>
       other is Configuration && name == other.name && optionsEqual(other);
 
@@ -403,10 +426,12 @@
       mode.hashCode ^
       runtime.hashCode ^
       system.hashCode ^
+      nnbdMode.hashCode ^
       babel.hashCode ^
       builderTag.hashCode ^
       vmOptions.join(" & ").hashCode ^
       dart2jsOptions.join(" & ").hashCode ^
+      experiments.join(" & ").hashCode ^
       timeout.hashCode ^
       _toBinary([
         enableAsserts,
@@ -414,7 +439,6 @@
         isCsp,
         isHostChecked,
         isMinified,
-        previewDart2,
         useAnalyzerCfe,
         useAnalyzerFastaParser,
         useBlobs,
@@ -425,7 +449,7 @@
       ]);
 
   String toString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     buffer.write(name);
     buffer.write("(");
 
@@ -436,19 +460,24 @@
     fields.add("runtime: $runtime");
     fields.add("system: $system");
 
+    if (nnbdMode != NnbdMode.legacy) fields.add("nnbd: $nnbdMode");
+
+    stringListField(String name, List<String> field) {
+      if (field.isEmpty) return;
+      fields.add("$name: [${field.join(", ")}]");
+    }
+
     if (babel.isNotEmpty) fields.add("babel: $babel");
     if (builderTag.isNotEmpty) fields.add("builder-tag: $builderTag");
-    if (vmOptions.isNotEmpty)
-      fields.add("vm-options: [${vmOptions.join(", ")}]");
-    if (dart2jsOptions.isNotEmpty)
-      fields.add("dart2js-options: [${dart2jsOptions.join(", ")}]");
+    stringListField("vm-options", vmOptions);
+    stringListField("dart2js-options", dart2jsOptions);
+    stringListField("experiments", experiments);
     if (timeout > 0) fields.add("timeout: $timeout");
     if (enableAsserts) fields.add("enable-asserts");
     if (isChecked) fields.add("checked");
     if (isCsp) fields.add("csp");
     if (isHostChecked) fields.add("host-checked");
     if (isMinified) fields.add("minified");
-    if (previewDart2) fields.add("preview-dart-2");
     if (useAnalyzerCfe) fields.add("use-cfe");
     if (useAnalyzerFastaParser) fields.add("analyzer-use-fasta-parser");
     if (useBlobs) fields.add("use-blobs");
@@ -462,7 +491,7 @@
   }
 
   String visualCompare(Configuration other) {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     buffer.writeln(name);
     buffer.writeln(other.name);
 
@@ -473,68 +502,44 @@
     fields.add("runtime: $runtime ${other.runtime}");
     fields.add("system: $system ${other.system}");
 
-    if (babel.isNotEmpty || other.babel.isNotEmpty) {
-      var ours = babel == "" ? "(none)" : babel;
-      var theirs = other.babel == "" ? "(none)" : other.babel;
-      fields.add("babel: $ours $theirs");
+    stringField(String name, String value, String otherValue) {
+      if (value.isEmpty && otherValue.isEmpty) return;
+      var ours = value.isEmpty ? "(none)" : value;
+      var theirs = otherValue.isEmpty ? "(none)" : otherValue;
+      fields.add("$name: $ours $theirs");
     }
-    if (builderTag.isNotEmpty || other.builderTag.isNotEmpty) {
-      var ours = builderTag == "" ? "(none)" : builderTag;
-      var theirs = other.builderTag == "" ? "(none)" : other.builderTag;
-      fields.add("builder-tag: $ours $theirs");
+
+    stringListField(String name, List<String> value, List<String> otherValue) {
+      if (value.isEmpty && otherValue.isEmpty) return;
+      fields.add("$name: [${value.join(', ')}] [${otherValue.join(', ')}]");
     }
-    if (vmOptions.isNotEmpty || other.vmOptions.isNotEmpty) {
-      var ours = "[${vmOptions.join(", ")}]";
-      var theirs = "[${other.vmOptions.join(", ")}]";
-      fields.add("vm-options: $ours $theirs");
+
+    boolField(String name, bool value, bool otherValue) {
+      if (!value && !otherValue) return;
+      fields.add("$name: $value $otherValue");
     }
-    if (dart2jsOptions.isNotEmpty || other.dart2jsOptions.isNotEmpty) {
-      var ours = "[${dart2jsOptions.join(", ")}]";
-      var theirs = "[${other.dart2jsOptions.join(", ")}]";
-      fields.add("dart2js-options: $ours $theirs");
-    }
+
+    fields.add("nnbd: $nnbdMode ${other.nnbdMode}");
+    stringField("babel", babel, other.babel);
+    stringField("builder-tag", builderTag, other.builderTag);
+    stringListField("vm-options", vmOptions, other.vmOptions);
+    stringListField("dart2js-options", dart2jsOptions, other.dart2jsOptions);
+    stringListField("experiments", experiments, other.experiments);
     fields.add("timeout: $timeout ${other.timeout}");
-    if (enableAsserts || other.enableAsserts) {
-      fields.add("enable-asserts $enableAsserts ${other.enableAsserts}");
-    }
-    if (isChecked || other.isChecked) {
-      fields.add("checked $isChecked ${other.isChecked}");
-    }
-    if (isCsp || other.isCsp) {
-      fields.add("csp $isCsp ${other.isCsp}");
-    }
-    if (isHostChecked || other.isHostChecked) {
-      fields.add("isHostChecked $isHostChecked ${other.isHostChecked}");
-    }
-    if (isMinified || other.isMinified) {
-      fields.add("isMinified $isMinified ${other.isMinified}");
-    }
-    if (previewDart2 || other.previewDart2) {
-      fields.add("previewDart2 $previewDart2 ${other.previewDart2}");
-    }
-    if (useAnalyzerCfe || other.useAnalyzerCfe) {
-      fields.add("useAnalyzerCfe $useAnalyzerCfe ${other.useAnalyzerCfe}");
-    }
-    if (useAnalyzerFastaParser || other.useAnalyzerFastaParser) {
-      fields.add("useAnalyzerFastaParser "
-          "$useAnalyzerFastaParser ${other.useAnalyzerFastaParser}");
-    }
-    if (useBlobs || other.useBlobs) {
-      fields.add("useBlobs $useBlobs ${other.useBlobs}");
-    }
-    if (useHotReload || other.useHotReload) {
-      fields.add("useHotReload $useHotReload ${other.useHotReload}");
-    }
-    if (isHostChecked) {
-      fields.add("host-checked $isHostChecked ${other.isHostChecked}");
-    }
-    if (useHotReloadRollback || other.useHotReloadRollback) {
-      fields.add("useHotReloadRollback"
-          " $useHotReloadRollback ${other.useHotReloadRollback}");
-    }
-    if (useSdk || other.useSdk) {
-      fields.add("useSdk $useSdk ${other.useSdk}");
-    }
+    boolField("enable-asserts", enableAsserts, other.enableAsserts);
+    boolField("checked", isChecked, other.isChecked);
+    boolField("csp", isCsp, other.isCsp);
+    boolField("host-checked", isHostChecked, other.isHostChecked);
+    boolField("minified", isMinified, other.isMinified);
+    boolField("use-cfe", useAnalyzerCfe, other.useAnalyzerCfe);
+    boolField("analyzer-use-fasta-parser", useAnalyzerFastaParser,
+        other.useAnalyzerFastaParser);
+    boolField("use-blobs", useBlobs, other.useBlobs);
+    boolField("host-checked", isHostChecked, other.isHostChecked);
+    boolField("hot-reload", useHotReload, other.useHotReload);
+    boolField("hot-reload-rollback", useHotReloadRollback,
+        other.useHotReloadRollback);
+    boolField("use-sdk", useSdk, other.useSdk);
 
     buffer.write(fields.join("\n   "));
     buffer.write("\n");
@@ -543,22 +548,22 @@
 }
 
 class Architecture extends NamedEnum {
-  static const ia32 = const Architecture._('ia32');
-  static const x64 = const Architecture._('x64');
-  static const arm = const Architecture._('arm');
-  static const armv6 = const Architecture._('armv6');
-  static const armv5te = const Architecture._('armv5te');
-  static const arm64 = const Architecture._('arm64');
-  static const simarm = const Architecture._('simarm');
-  static const simarmv6 = const Architecture._('simarmv6');
-  static const simarmv5te = const Architecture._('simarmv5te');
-  static const simarm64 = const Architecture._('simarm64');
-  static const simdbc = const Architecture._('simdbc');
-  static const simdbc64 = const Architecture._('simdbc64');
+  static const ia32 = Architecture._('ia32');
+  static const x64 = Architecture._('x64');
+  static const arm = Architecture._('arm');
+  static const armv6 = Architecture._('armv6');
+  static const armv5te = Architecture._('armv5te');
+  static const arm64 = Architecture._('arm64');
+  static const simarm = Architecture._('simarm');
+  static const simarmv6 = Architecture._('simarmv6');
+  static const simarmv5te = Architecture._('simarmv5te');
+  static const simarm64 = Architecture._('simarm64');
+  static const simdbc = Architecture._('simdbc');
+  static const simdbc64 = Architecture._('simdbc64');
 
   static final List<String> names = _all.keys.toList();
 
-  static final _all = new Map<String, Architecture>.fromIterable([
+  static final _all = Map<String, Architecture>.fromIterable([
     ia32,
     x64,
     arm,
@@ -577,29 +582,29 @@
     var architecture = _all[name];
     if (architecture != null) return architecture;
 
-    throw new ArgumentError('Unknown architecture "$name".');
+    throw ArgumentError('Unknown architecture "$name".');
   }
 
   const Architecture._(String name) : super(name);
 }
 
 class Compiler extends NamedEnum {
-  static const none = const Compiler._('none');
-  static const dart2js = const Compiler._('dart2js');
-  static const dart2analyzer = const Compiler._('dart2analyzer');
-  static const compareAnalyzerCfe = const Compiler._('compare_analyzer_cfe');
-  static const dartdevc = const Compiler._('dartdevc');
-  static const dartdevk = const Compiler._('dartdevk');
-  static const appJitk = const Compiler._('app_jitk');
-  static const dartk = const Compiler._('dartk');
-  static const dartkp = const Compiler._('dartkp');
-  static const dartkb = const Compiler._('dartkb');
-  static const specParser = const Compiler._('spec_parser');
-  static const fasta = const Compiler._('fasta');
+  static const none = Compiler._('none');
+  static const dart2js = Compiler._('dart2js');
+  static const dart2analyzer = Compiler._('dart2analyzer');
+  static const compareAnalyzerCfe = Compiler._('compare_analyzer_cfe');
+  static const dartdevc = Compiler._('dartdevc');
+  static const dartdevk = Compiler._('dartdevk');
+  static const appJitk = Compiler._('app_jitk');
+  static const dartk = Compiler._('dartk');
+  static const dartkp = Compiler._('dartkp');
+  static const dartkb = Compiler._('dartkb');
+  static const specParser = Compiler._('spec_parser');
+  static const fasta = Compiler._('fasta');
 
   static final List<String> names = _all.keys.toList();
 
-  static final _all = new Map<String, Compiler>.fromIterable([
+  static final _all = Map<String, Compiler>.fromIterable([
     none,
     dart2js,
     dart2analyzer,
@@ -618,7 +623,7 @@
     var compiler = _all[name];
     if (compiler != null) return compiler;
 
-    throw new ArgumentError('Unknown compiler "$name".');
+    throw ArgumentError('Unknown compiler "$name".');
   }
 
   const Compiler._(String name) : super(name);
@@ -722,21 +727,20 @@
 }
 
 class Mode extends NamedEnum {
-  static const debug = const Mode._('debug');
-  static const product = const Mode._('product');
-  static const release = const Mode._('release');
+  static const debug = Mode._('debug');
+  static const product = Mode._('product');
+  static const release = Mode._('release');
 
   static final List<String> names = _all.keys.toList();
 
-  static final _all = new Map<String, Mode>.fromIterable(
-      [debug, product, release],
+  static final _all = Map<String, Mode>.fromIterable([debug, product, release],
       key: (mode) => (mode as Mode).name);
 
   static Mode find(String name) {
     var mode = _all[name];
     if (mode != null) return mode;
 
-    throw new ArgumentError('Unknown mode "$name".');
+    throw ArgumentError('Unknown mode "$name".');
   }
 
   const Mode._(String name) : super(name);
@@ -745,25 +749,25 @@
 }
 
 class Runtime extends NamedEnum {
-  static const vm = const Runtime._('vm');
-  static const flutter = const Runtime._('flutter');
-  static const dartPrecompiled = const Runtime._('dart_precompiled');
-  static const d8 = const Runtime._('d8');
-  static const jsshell = const Runtime._('jsshell');
-  static const firefox = const Runtime._('firefox');
-  static const chrome = const Runtime._('chrome');
-  static const safari = const Runtime._('safari');
-  static const ie9 = const Runtime._('ie9');
-  static const ie10 = const Runtime._('ie10');
-  static const ie11 = const Runtime._('ie11');
-  static const edge = const Runtime._('edge');
-  static const chromeOnAndroid = const Runtime._('chromeOnAndroid');
-  static const selfCheck = const Runtime._('self_check');
-  static const none = const Runtime._('none');
+  static const vm = Runtime._('vm');
+  static const flutter = Runtime._('flutter');
+  static const dartPrecompiled = Runtime._('dart_precompiled');
+  static const d8 = Runtime._('d8');
+  static const jsshell = Runtime._('jsshell');
+  static const firefox = Runtime._('firefox');
+  static const chrome = Runtime._('chrome');
+  static const safari = Runtime._('safari');
+  static const ie9 = Runtime._('ie9');
+  static const ie10 = Runtime._('ie10');
+  static const ie11 = Runtime._('ie11');
+  static const edge = Runtime._('edge');
+  static const chromeOnAndroid = Runtime._('chromeOnAndroid');
+  static const selfCheck = Runtime._('self_check');
+  static const none = Runtime._('none');
 
   static final List<String> names = _all.keys.toList();
 
-  static final _all = new Map<String, Runtime>.fromIterable([
+  static final _all = Map<String, Runtime>.fromIterable([
     vm,
     flutter,
     dartPrecompiled,
@@ -785,7 +789,7 @@
     var runtime = _all[name];
     if (runtime != null) return runtime;
 
-    throw new ArgumentError('Unknown runtime "$name".');
+    throw ArgumentError('Unknown runtime "$name".');
   }
 
   const Runtime._(String name) : super(name);
@@ -847,15 +851,15 @@
 }
 
 class System extends NamedEnum {
-  static const android = const System._('android');
-  static const fuchsia = const System._('fuchsia');
-  static const linux = const System._('linux');
-  static const mac = const System._('mac');
-  static const win = const System._('win');
+  static const android = System._('android');
+  static const fuchsia = System._('fuchsia');
+  static const linux = System._('linux');
+  static const mac = System._('mac');
+  static const win = System._('win');
 
   static final List<String> names = _all.keys.toList();
 
-  static final _all = new Map<String, System>.fromIterable(
+  static final _all = Map<String, System>.fromIterable(
       [android, fuchsia, linux, mac, win],
       key: (system) => (system as System).name);
 
@@ -875,7 +879,7 @@
     }
     // TODO(rnystrom): What about ios?
 
-    throw new ArgumentError('Unknown operating system "$name".');
+    throw ArgumentError('Unknown operating system "$name".');
   }
 
   const System._(String name) : super(name);
@@ -897,6 +901,34 @@
   }
 }
 
+/// What level of non-nullability support should be applied to the test files.
+class NnbdMode extends NamedEnum {
+  /// "Opted out" legacy mode with no NNBD features allowed.
+  static const legacy = NnbdMode._('legacy');
+
+  /// Opted in to NNBD features, but only static checking and weak runtime
+  /// checks.
+  static const optedIn = NnbdMode._('opted-in');
+
+  /// Opted in to NNBD features and with full sound runtime checks.
+  static const strong = NnbdMode._('strong');
+
+  static final List<String> names = _all.keys.toList();
+
+  static final _all = {
+    for (var mode in [legacy, optedIn, strong]) mode.name: mode
+  };
+
+  static NnbdMode find(String name) {
+    var mode = _all[name];
+    if (mode != null) return mode;
+
+    throw ArgumentError('Unknown NNBD mode "$name".');
+  }
+
+  const NnbdMode._(String name) : super(name);
+}
+
 /// Base class for an enum-like class whose values are identified by name.
 abstract class NamedEnum {
   final String name;
diff --git a/pkg/smith/lib/test_matrix.dart b/pkg/smith/lib/test_matrix.dart
index 0bf2a5b..74adce7 100644
--- a/pkg/smith/lib/test_matrix.dart
+++ b/pkg/smith/lib/test_matrix.dart
@@ -13,7 +13,7 @@
 
   /// Reads a test matrix from the file at [path].
   static TestMatrix fromPath(String path) {
-    var json = jsonDecode(new File(path).readAsStringSync());
+    var json = jsonDecode(File(path).readAsStringSync());
     return fromJson(json as Map<String, dynamic>);
   }
 
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index 9c77fb3..fcbbebf 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -198,39 +198,35 @@
       test("other options from map", () {
         expect(
             Configuration.parse("dart2js", {
+              "nnbd": "opted-in",
               "builder-tag": "the tag",
               "vm-options": ["vm stuff", "more vm stuff"],
               "dart2js-options": ["dart2js stuff", "more dart2js stuff"],
+              "experiments": ["semicolons", "interrobangs"],
               "enable-asserts": true,
               "checked": true,
               "csp": true,
               "host-checked": true,
               "minified": true,
-              "preview-dart-2": true,
               "hot-reload": true,
               "hot-reload-rollback": true,
-              "use-sdk": true,
+              "use-sdk": true
             }),
-            equals(Configuration(
-              "dart2js",
-              Architecture.x64,
-              Compiler.dart2js,
-              Mode.release,
-              Runtime.d8,
-              System.host,
-              builderTag: "the tag",
-              vmOptions: ["vm stuff", "more vm stuff"],
-              dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
-              enableAsserts: true,
-              isChecked: true,
-              isCsp: true,
-              isHostChecked: true,
-              isMinified: true,
-              previewDart2: true,
-              useHotReload: true,
-              useHotReloadRollback: true,
-              useSdk: true,
-            )));
+            equals(Configuration("dart2js", Architecture.x64, Compiler.dart2js,
+                Mode.release, Runtime.d8, System.host,
+                nnbdMode: NnbdMode.optedIn,
+                builderTag: "the tag",
+                vmOptions: ["vm stuff", "more vm stuff"],
+                dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
+                experiments: ["semicolons", "interrobangs"],
+                enableAsserts: true,
+                isChecked: true,
+                isCsp: true,
+                isHostChecked: true,
+                isMinified: true,
+                useHotReload: true,
+                useHotReloadRollback: true,
+                useSdk: true)));
       });
 
       test("neither compiler nor runtime specified", () {
@@ -238,7 +234,7 @@
             "debug",
             {},
             'Must specify at least one of compiler or runtime in options or '
-            'configuration name.');
+                'configuration name.');
       });
 
       test("empty string", () {
@@ -255,7 +251,7 @@
             "dart2js-debug",
             {"mode": "release"},
             'Found mode "release" in options and "debug" in configuration '
-            'name.');
+                'name.');
       });
 
       test("multiple values for same option in name", () {
@@ -263,7 +259,7 @@
             "dart2js-debug-release",
             {},
             'Found multiple values for mode ("debug" and "release"), in '
-            'configuration name.');
+                'configuration name.');
       });
 
       test("null bool option", () {
@@ -341,6 +337,103 @@
       test("same options are equal", () {
         expect(debugWithAsserts.optionsEqual(debugWithAsserts2), isTrue);
       });
+
+      test("list elements are considered unordered", () {
+        var aThenB = Configuration("name", Architecture.x64, Compiler.dart2js,
+            Mode.release, Runtime.vm, System.linux,
+            vmOptions: ["a", "b"]);
+
+        var bThenA = Configuration("name", Architecture.x64, Compiler.dart2js,
+            Mode.release, Runtime.vm, System.linux,
+            vmOptions: ["b", "a"]);
+
+        expect(aThenB.optionsEqual(bThenA), isTrue);
+      });
+    });
+
+    group("visualCompare()", () {
+      var a = Configuration("dartdevc", Architecture.ia32, Compiler.dartdevc,
+          Mode.debug, Runtime.chrome, System.android,
+          builderTag: "a tag",
+          vmOptions: ["vm a1", "vm a2"],
+          dart2jsOptions: ["dart2js a1", "dart2js a2"],
+          experiments: ["experiment a1", "experiment a2"],
+          timeout: 1);
+
+      var b = Configuration(
+        "dart2js",
+        Architecture.x64,
+        Compiler.dart2js,
+        Mode.release,
+        Runtime.d8,
+        System.fuchsia,
+        nnbdMode: NnbdMode.strong,
+        builderTag: "b tag",
+        vmOptions: ["vm b1", "vm b2"],
+        dart2jsOptions: ["dart2js b1", "dart2js b2"],
+        experiments: ["experiment b1", "experiment b2"],
+        timeout: 2,
+        enableAsserts: true,
+        isChecked: true,
+        isCsp: true,
+        isHostChecked: true,
+        isMinified: true,
+        useAnalyzerCfe: true,
+        useAnalyzerFastaParser: true,
+        useBlobs: true,
+        useElf: true,
+        useHotReload: true,
+        useHotReloadRollback: true,
+        useSdk: true,
+      );
+
+      test("everything different", () {
+        expect(a.visualCompare(b), equals("""
+dartdevc
+dart2js
+architecture: ia32 x64
+   compiler: dartdevc dart2js
+   mode: debug release
+   runtime: chrome d8
+   system: android fuchsia
+   nnbd: legacy strong
+   builder-tag: a tag b tag
+   vm-options: [vm a1, vm a2] [vm b1, vm b2]
+   dart2js-options: [dart2js a1, dart2js a2] [dart2js b1, dart2js b2]
+   experiments: [experiment a1, experiment a2] [experiment b1, experiment b2]
+   timeout: 1 2
+   enable-asserts: false true
+   checked: false true
+   csp: false true
+   host-checked: false true
+   minified: false true
+   use-cfe: false true
+   analyzer-use-fasta-parser: false true
+   use-blobs: false true
+   host-checked: false true
+   hot-reload: false true
+   hot-reload-rollback: false true
+   use-sdk: false true
+"""));
+      });
+
+      test("everything the same", () {
+        expect(a.visualCompare(a), equals("""
+dartdevc
+dartdevc
+architecture: ia32 ia32
+   compiler: dartdevc dartdevc
+   mode: debug debug
+   runtime: chrome chrome
+   system: android android
+   nnbd: legacy legacy
+   builder-tag: a tag a tag
+   vm-options: [vm a1, vm a2] [vm a1, vm a2]
+   dart2js-options: [dart2js a1, dart2js a2] [dart2js a1, dart2js a2]
+   experiments: [experiment a1, experiment a2] [experiment a1, experiment a2]
+   timeout: 1 1
+"""));
+      });
     });
   });
 }
diff --git a/pkg/status_file/bin/remove_non_essential_entries.dart b/pkg/status_file/bin/remove_non_essential_entries.dart
index 80cd930..409fbcd 100644
--- a/pkg/status_file/bin/remove_non_essential_entries.dart
+++ b/pkg/status_file/bin/remove_non_essential_entries.dart
@@ -19,6 +19,14 @@
 //
 // When using the option to keep crashes, there will be an additional line
 //   a: Crash
+//
+// The option -r can be used to also process expectations in lines with
+// comments. In this mode, deleted comments are collected and either printed
+// out or written to a separate file (with -w).
+//
+// The option -i (with -r) tries to resolve the status of issues mentioned in
+// comments and adds it to the collected comments. This requires an issue.log
+// file as described in [parseIssueFile].
 
 import 'dart:io';
 
@@ -37,8 +45,93 @@
       : StatusEntry(entry.path, entry.lineNumber, remaining, entry.comment);
 }
 
-StatusFile removeNonEssentialEntries(
-    StatusFile statusFile, List<Expectation> expectationsToKeep) {
+Map<String, Map<int, String>> issues;
+
+String getIssueState(String project, int issue) {
+  Map projectIssues = issues[project];
+  if (projectIssues == null) {
+    throw "Cannot find project $project, not one of {${issues.keys.join(",")}}";
+  }
+  String state = projectIssues[issue] ?? "";
+  return "\t$state";
+}
+
+// This method assumes the following data format:
+//  <project>, <state>, <issue number>, <update timestamp>
+// sorted by issue number then timestamp ascending.
+//
+// The first line is expected to contain the field names and is skipped.
+void parseIssueFile() async {
+  issues = {};
+  String issuesLog = await File("issues.log").readAsString();
+  List<String> lines = issuesLog.split("\n");
+  for (String line in lines.skip(1).where((line) => line.isNotEmpty)) {
+    List<String> fields = line.split(",");
+    if (fields.length != 4) {
+      throw "invalid issue state line $line";
+    }
+    String project = fields[0];
+    String state = fields[1];
+    int issueNumber = int.parse(fields[2]);
+    issues.putIfAbsent(project, () => {})[issueNumber] = state;
+  }
+}
+
+List<RegExp> co19IssuePatterns = [
+  RegExp(r"https://github.com/dart-lang/co19/issues/(\d+)"),
+  RegExp(r"co19 issue (\d+)"),
+];
+
+List<RegExp> sdkIssuePatterns = [
+  RegExp(r"[Ii]ssue (\d+)"),
+  RegExp(r"#(\d+)"),
+  RegExp(r"^(\d+)$"),
+  RegExp(r"http://dartbug.com/(\d+)"),
+  RegExp(r"https://github.com/dart-lang/sdk/issues/(\d+)"),
+];
+
+String getIssueText(String comment, bool resolveState) {
+  int issue;
+  String prefix;
+  String project;
+  for (RegExp pattern in co19IssuePatterns) {
+    Match match = pattern.firstMatch(comment);
+    if (match != null) {
+      issue = int.tryParse(match[1]);
+      if (issue != null) {
+        prefix = "https://github.com/dart-lang/co19/issues/";
+        project = "dart-lang/co19";
+        break;
+      }
+    }
+  }
+  if (issue == null) {
+    for (RegExp pattern in sdkIssuePatterns) {
+      Match match = pattern.firstMatch(comment);
+      if (match != null) {
+        issue = int.tryParse(match[1]);
+        if (issue != null) {
+          prefix = "https://dartbug.com/";
+          project = "dart-lang/sdk";
+          break;
+        }
+      }
+    }
+  }
+  if (issue != null) {
+    String state = resolveState ? getIssueState(project, issue) : "";
+    return "$prefix$issue$state";
+  } else {
+    return "";
+  }
+}
+
+Future<StatusFile> removeNonEssentialEntries(
+    StatusFile statusFile,
+    List<Expectation> expectationsToKeep,
+    bool removeComments,
+    List<String> comments,
+    bool resolveIssueState) async {
   List<StatusSection> sections = <StatusSection>[];
   for (StatusSection section in statusFile.sections) {
     bool hasStatusEntries = false;
@@ -46,12 +139,30 @@
     for (Entry entry in section.entries) {
       if (entry is EmptyEntry) {
         entries.add(entry);
-      } else if (entry is StatusEntry && entry.comment != null ||
-          entry is CommentEntry) {
+      } else if (entry is CommentEntry) {
         entries.add(entry);
         hasStatusEntries = true;
       } else if (entry is StatusEntry) {
-        StatusEntry newEntry = filterExpectations(entry, expectationsToKeep);
+        StatusEntry newEntry = entry;
+        if (entry.comment == null) {
+          newEntry = filterExpectations(entry, expectationsToKeep);
+        } else if (removeComments) {
+          newEntry = filterExpectations(entry, expectationsToKeep);
+          // Store comment if entry will be removed.
+          if (newEntry == null) {
+            String comment = entry.comment.toString().substring(1).trim();
+            String testName = entry.path;
+            String expectations = entry.expectations.toString();
+            // Remove '[' and ']'.
+            expectations = expectations.substring(1, expectations.length - 1);
+            String conditionPrefix =
+                section.condition != null ? "${section.condition}" : "";
+            String issueText = await getIssueText(comment, resolveIssueState);
+            String statusLine = "$conditionPrefix\t$testName\t$expectations"
+                "\t$comment\t$issueText";
+            comments.add(statusLine);
+          }
+        }
         if (newEntry != null) {
           entries.add(newEntry);
           hasStatusEntries = true;
@@ -83,6 +194,10 @@
       help: "Overwrite input file with output.");
   parser.addFlag("keep-crashes",
       abbr: 'c', negatable: false, defaultsTo: false);
+  parser.addFlag("remove-comments",
+      abbr: 'r', negatable: false, defaultsTo: false);
+  parser.addFlag("resolve-issue-states",
+      abbr: 'i', negatable: false, defaultsTo: false);
   parser.addFlag("help",
       abbr: "h",
       negatable: false,
@@ -97,7 +212,15 @@
   print(parser.usage);
 }
 
-main(List<String> arguments) {
+String formatComments(List<String> comments) {
+  StringBuffer sb = new StringBuffer();
+  for (String statusLine in comments) {
+    sb.writeln(statusLine);
+  }
+  return sb.toString();
+}
+
+main(List<String> arguments) async {
   var parser = buildParser();
   var results = parser.parse(arguments);
   if (results["help"] || results.rest.isEmpty) {
@@ -117,15 +240,32 @@
     expectationsToKeep.add(Expectation.crash);
   }
 
+  bool removeComments = results["remove-comments"];
+
   for (String path in results.rest) {
+    List<String> comments = [];
+
     bool writeFile = results["overwrite"];
+    bool resolveGithubIssueState = results["resolve-issue-states"];
     var statusFile = StatusFile.read(path);
-    statusFile = removeNonEssentialEntries(statusFile, expectationsToKeep);
+    if (resolveGithubIssueState) {
+      await parseIssueFile();
+    }
+    statusFile = await removeNonEssentialEntries(statusFile, expectationsToKeep,
+        removeComments, comments, resolveGithubIssueState);
     if (writeFile) {
-      File(path).writeAsStringSync(statusFile.toString());
-      print("Modified $path.");
+      await File(path).writeAsString(statusFile.toString());
+      print("Wrote $path.");
+      if (removeComments) {
+        await File("$path.csv").writeAsString(formatComments(comments));
+        print("Wrote $path.csv.");
+      }
     } else {
       print(statusFile);
+      if (removeComments) {
+        print("");
+        print(formatComments(comments));
+      }
     }
   }
 }
diff --git a/pkg/test_runner/lib/src/browser_controller.dart b/pkg/test_runner/lib/src/browser_controller.dart
index 9f7cabc..4467399 100644
--- a/pkg/test_runner/lib/src/browser_controller.dart
+++ b/pkg/test_runner/lib/src/browser_controller.dart
@@ -200,7 +200,7 @@
           .listen(_addStdout, onError: (error) {
         // This should _never_ happen, but we really want this in the log
         // if it actually does due to dart:io or vm bug.
-        _logEvent("An error occured in the process stdout handling: $error");
+        _logEvent("An error occurred in the process stdout handling: $error");
       }, onDone: closeStdout);
 
       stderrSubscription = process.stderr
@@ -208,7 +208,7 @@
           .listen(_addStderr, onError: (error) {
         // This should _never_ happen, but we really want this in the log
         // if it actually does due to dart:io or vm bug.
-        _logEvent("An error occured in the process stderr handling: $error");
+        _logEvent("An error occurred in the process stderr handling: $error");
       }, onDone: closeStderr);
 
       process.exitCode.then((exitCode) {
@@ -1200,7 +1200,7 @@
     }
 
     void errorHandler(e) {
-      if (!underTermination) print("Error occured in httpserver: $e");
+      if (!underTermination) print("Error occurred in httpserver: $e");
     }
 
     errorReportingServer.listen(errorReportingHandler, onError: errorHandler);
diff --git a/pkg/test_runner/lib/src/command.dart b/pkg/test_runner/lib/src/command.dart
index c3427a2..6732b5b 100644
--- a/pkg/test_runner/lib/src/command.dart
+++ b/pkg/test_runner/lib/src/command.dart
@@ -7,138 +7,24 @@
 // CommandOutput.exitCode in subclasses of CommandOutput.
 import 'dart:io' as io;
 
-import 'package:status_file/expectation.dart';
-
 import 'command_output.dart';
 import 'configuration.dart';
 import 'path.dart';
 import 'utils.dart';
 
 /// A command executed as a step in a test case.
-class Command {
+abstract class Command {
   static Command browserTest(String url, TestConfiguration configuration,
       {bool retry}) {
     return BrowserTestCommand._(url, configuration, retry);
   }
 
-  static Command compilation(
-      String displayName,
-      String outputFile,
-      List<Uri> bootstrapDependencies,
-      String executable,
-      List<String> arguments,
-      Map<String, String> environment,
-      {bool alwaysCompile = false,
-      String workingDirectory}) {
-    return CompilationCommand._(displayName, outputFile, alwaysCompile,
-        bootstrapDependencies, executable, arguments, environment,
-        workingDirectory: workingDirectory);
-  }
-
-  static Command vmKernelCompilation(
-      String outputFile,
-      bool neverSkipCompilation,
-      List<Uri> bootstrapDependencies,
-      String executable,
-      List<String> arguments,
-      Map<String, String> environment,
-      List<String> batchArgs) {
-    return VMKernelCompilationCommand._(outputFile, neverSkipCompilation,
-        bootstrapDependencies, executable, arguments, environment, batchArgs);
-  }
-
-  static Command analysis(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides) {
-    return AnalysisCommand._(executable, arguments, environmentOverrides);
-  }
-
-  static Command compareAnalyzerCfe(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides) {
-    return CompareAnalyzerCfeCommand._(
-        executable, arguments, environmentOverrides);
-  }
-
-  static Command specParse(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides) {
-    return SpecParseCommand._(executable, arguments, environmentOverrides);
-  }
-
-  static Command vm(String executable, List<String> arguments,
-      Map<String, String> environmentOverrides) {
-    return VmCommand._(executable, arguments, environmentOverrides);
-  }
-
-  static Command vmBatch(String executable, String tester,
-      List<String> arguments, Map<String, String> environmentOverrides,
-      {bool checked = true}) {
-    return VmBatchCommand._(executable, tester, arguments, environmentOverrides,
-        checked: checked);
-  }
-
-  static Command adbPrecompiled(
-      String buildPath,
-      String processTest,
-      String testDirectory,
-      List<String> arguments,
-      bool useBlobs,
-      bool useElf,
-      List<String> extraLibs) {
-    return AdbPrecompilationCommand._(buildPath, processTest, testDirectory,
-        arguments, useBlobs, useElf, extraLibs);
-  }
-
-  static Command adbDartk(String buildPath, String processTest, String script,
-      List<String> arguments, List<String> extraLibraries) {
-    return AdbDartkCommand._(
-        buildPath, processTest, script, arguments, extraLibraries);
-  }
-
-  static Command jsCommandLine(
-      String displayName, String executable, List<String> arguments,
-      [Map<String, String> environment]) {
-    return JSCommandlineCommand._(
-        displayName, executable, arguments, environment);
-  }
-
-  static Command process(
-      String displayName, String executable, List<String> arguments,
-      [Map<String, String> environment, String workingDirectory]) {
-    return ProcessCommand._(
-        displayName, executable, arguments, environment, workingDirectory);
-  }
-
-  static Command copy(String sourceDirectory, String destinationDirectory) {
-    return CleanDirectoryCopyCommand._(sourceDirectory, destinationDirectory);
-  }
-
-  static Command makeSymlink(String link, String target) {
-    return MakeSymlinkCommand._(link, target);
-  }
-
-  static Command fasta(
-      Uri compilerLocation,
-      Uri outputFile,
-      List<Uri> bootstrapDependencies,
-      Uri executable,
-      List<String> arguments,
-      Map<String, String> environment,
-      Uri workingDirectory) {
-    return FastaCompilationCommand._(
-        compilerLocation,
-        outputFile.toFilePath(),
-        bootstrapDependencies,
-        executable.toFilePath(),
-        arguments,
-        environment,
-        workingDirectory?.toFilePath());
-  }
-
   /// A descriptive name for this command.
   final String displayName;
 
   /// When cloning a command object to run it multiple times, we give
   /// the different copies distinct values for index.
-  int index;
+  final int index;
 
   /// Number of times this command *can* be retried.
   int get maxNumRetries => 2;
@@ -156,9 +42,13 @@
   /// Two clones with the same index will be equal, with different indices
   /// will be distinct. Used to run tests multiple times, since identical
   /// commands are only run once by the dependency graph scheduler.
-  Command indexedCopy(int index) {
-    return Command._(displayName, index: index);
-  }
+  Command indexedCopy(int index);
+
+  CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+          List<int> stderr, Duration time, bool compilationSkipped,
+          [int pid = 0]) =>
+      CommandOutput(this, exitCode, timedOut, stdout, stderr, time,
+          compilationSkipped, pid);
 
   int get hashCode {
     if (_cachedHashCode == null) {
@@ -174,7 +64,7 @@
       (runtimeType == other.runtimeType && _equal(other as Command));
 
   void _buildHashCode(HashCodeBuilder builder) {
-    builder.addJson(displayName);
+    builder.add(displayName);
     builder.add(index);
   }
 
@@ -201,7 +91,7 @@
   /// Working directory for the command.
   final String workingDirectory;
 
-  ProcessCommand._(String displayName, this.executable, this.arguments,
+  ProcessCommand(String displayName, this.executable, this.arguments,
       [this.environmentOverrides, this.workingDirectory, int index = 0])
       : super._(displayName, index: index) {
     if (io.Platform.operatingSystem == 'windows') {
@@ -213,7 +103,7 @@
   }
 
   ProcessCommand indexedCopy(int index) {
-    return ProcessCommand._(displayName, executable, arguments,
+    return ProcessCommand(displayName, executable, arguments,
         environmentOverrides, workingDirectory, index);
   }
 
@@ -264,30 +154,46 @@
   final bool _alwaysCompile;
   final List<Uri> _bootstrapDependencies;
 
-  CompilationCommand._(
+  CompilationCommand(
       String displayName,
       this.outputFile,
-      this._alwaysCompile,
       this._bootstrapDependencies,
       String executable,
       List<String> arguments,
       Map<String, String> environmentOverrides,
-      {String workingDirectory,
+      {bool alwaysCompile,
+      String workingDirectory,
       int index = 0})
-      : super._(displayName, executable, arguments, environmentOverrides,
+      : _alwaysCompile = alwaysCompile ?? false,
+        super(displayName, executable, arguments, environmentOverrides,
             workingDirectory, index);
 
-  CompilationCommand indexedCopy(int index) => CompilationCommand._(
+  CompilationCommand indexedCopy(int index) => CompilationCommand(
       displayName,
       outputFile,
-      _alwaysCompile,
       _bootstrapDependencies,
       executable,
       arguments,
       environmentOverrides,
+      alwaysCompile: _alwaysCompile,
       workingDirectory: workingDirectory,
       index: index);
 
+  CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+      List<int> stderr, Duration time, bool compilationSkipped,
+      [int pid = 0]) {
+    if (displayName == 'precompiler' || displayName == 'app_jit') {
+      return VMCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, pid);
+    } else if (displayName == 'dartdevc') {
+      return DevCompilerCommandOutput(this, exitCode, timedOut, stdout, stderr,
+          time, compilationSkipped, pid);
+    }
+
+    return CompilationCommandOutput(
+        this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
+  }
+
   bool get outputIsUpToDate {
     if (_alwaysCompile) return false;
 
@@ -336,7 +242,7 @@
 class FastaCompilationCommand extends CompilationCommand {
   final Uri _compilerLocation;
 
-  FastaCompilationCommand._(
+  FastaCompilationCommand(
       this._compilerLocation,
       String outputFile,
       List<Uri> bootstrapDependencies,
@@ -345,12 +251,14 @@
       Map<String, String> environmentOverrides,
       String workingDirectory,
       {int index = 0})
-      : super._("fasta", outputFile, true, bootstrapDependencies, executable,
-            arguments, environmentOverrides,
-            workingDirectory: workingDirectory, index: index);
+      : super("fasta", outputFile, bootstrapDependencies, executable, arguments,
+            environmentOverrides,
+            alwaysCompile: true,
+            workingDirectory: workingDirectory,
+            index: index);
 
   @override
-  FastaCompilationCommand indexedCopy(int index) => FastaCompilationCommand._(
+  FastaCompilationCommand indexedCopy(int index) => FastaCompilationCommand(
       _compilerLocation,
       outputFile,
       _bootstrapDependencies,
@@ -360,6 +268,12 @@
       workingDirectory,
       index: index);
 
+  FastaCommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+          List<int> stderr, Duration time, bool compilationSkipped,
+          [int pid = 0]) =>
+      FastaCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
+
   @override
   List<String> get batchArguments {
     return <String>[
@@ -427,29 +341,34 @@
 class VMKernelCompilationCommand extends CompilationCommand {
   final List<String> batchArgs;
 
-  VMKernelCompilationCommand._(
+  VMKernelCompilationCommand(
       String outputFile,
-      bool alwaysCompile,
       List<Uri> bootstrapDependencies,
       String executable,
       List<String> arguments,
       Map<String, String> environmentOverrides,
       this.batchArgs,
-      {int index = 0})
-      : super._('vm_compile_to_kernel $batchArgs', outputFile, alwaysCompile,
+      {bool alwaysCompile,
+      int index = 0})
+      : super('vm_compile_to_kernel $batchArgs', outputFile,
             bootstrapDependencies, executable, arguments, environmentOverrides,
-            index: index);
+            alwaysCompile: alwaysCompile, index: index);
 
   VMKernelCompilationCommand indexedCopy(int index) =>
-      VMKernelCompilationCommand._(
-          outputFile,
-          _alwaysCompile,
-          _bootstrapDependencies,
-          executable,
-          arguments,
-          environmentOverrides,
-          batchArgs,
-          index: index);
+      VMKernelCompilationCommand(outputFile, _bootstrapDependencies, executable,
+          arguments, environmentOverrides, batchArgs,
+          alwaysCompile: _alwaysCompile, index: index);
+
+  VMKernelCompilationCommandOutput createOutput(
+          int exitCode,
+          bool timedOut,
+          List<int> stdout,
+          List<int> stderr,
+          Duration time,
+          bool compilationSkipped,
+          [int pid = 0]) =>
+      VMKernelCompilationCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
 
   int get maxNumRetries => 1;
 
@@ -512,61 +431,94 @@
 }
 
 class AnalysisCommand extends ProcessCommand {
-  AnalysisCommand._(String executable, List<String> arguments,
+  AnalysisCommand(String executable, List<String> arguments,
       Map<String, String> environmentOverrides, {int index = 0})
-      : super._('dart2analyzer', executable, arguments, environmentOverrides,
+      : super('dart2analyzer', executable, arguments, environmentOverrides,
             null, index);
 
   AnalysisCommand indexedCopy(int index) =>
-      AnalysisCommand._(executable, arguments, environmentOverrides,
+      AnalysisCommand(executable, arguments, environmentOverrides,
           index: index);
+
+  CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+          List<int> stderr, Duration time, bool compilationSkipped,
+          [int pid = 0]) =>
+      AnalysisCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
 }
 
 class CompareAnalyzerCfeCommand extends ProcessCommand {
-  CompareAnalyzerCfeCommand._(String executable, List<String> arguments,
+  CompareAnalyzerCfeCommand(String executable, List<String> arguments,
       Map<String, String> environmentOverrides, {int index = 0})
-      : super._('compare_analyzer_cfe', executable, arguments,
+      : super('compare_analyzer_cfe', executable, arguments,
             environmentOverrides, null, index);
 
   CompareAnalyzerCfeCommand indexedCopy(int index) =>
-      CompareAnalyzerCfeCommand._(executable, arguments, environmentOverrides,
+      CompareAnalyzerCfeCommand(executable, arguments, environmentOverrides,
           index: index);
+
+  CompareAnalyzerCfeCommandOutput createOutput(
+          int exitCode,
+          bool timedOut,
+          List<int> stdout,
+          List<int> stderr,
+          Duration time,
+          bool compilationSkipped,
+          [int pid = 0]) =>
+      CompareAnalyzerCfeCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
 }
 
 class SpecParseCommand extends ProcessCommand {
-  SpecParseCommand._(String executable, List<String> arguments,
+  SpecParseCommand(String executable, List<String> arguments,
       Map<String, String> environmentOverrides, {int index = 0})
-      : super._('spec_parser', executable, arguments, environmentOverrides,
-            null, index);
+      : super('spec_parser', executable, arguments, environmentOverrides, null,
+            index);
 
   SpecParseCommand indexedCopy(int index) =>
-      SpecParseCommand._(executable, arguments, environmentOverrides,
+      SpecParseCommand(executable, arguments, environmentOverrides,
           index: index);
+
+  SpecParseCommandOutput createOutput(
+          int exitCode,
+          bool timedOut,
+          List<int> stdout,
+          List<int> stderr,
+          Duration time,
+          bool compilationSkipped,
+          [int pid = 0]) =>
+      SpecParseCommandOutput(
+          this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
 }
 
-class VmCommand extends ProcessCommand {
-  VmCommand._(String executable, List<String> arguments,
+class VMCommand extends ProcessCommand {
+  VMCommand(String executable, List<String> arguments,
       Map<String, String> environmentOverrides,
       {int index = 0})
-      : super._('vm', executable, arguments, environmentOverrides, null, index);
+      : super('vm', executable, arguments, environmentOverrides, null, index);
 
-  VmCommand indexedCopy(int index) =>
-      VmCommand._(executable, arguments, environmentOverrides, index: index);
+  VMCommand indexedCopy(int index) =>
+      VMCommand(executable, arguments, environmentOverrides, index: index);
+
+  CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+          List<int> stderr, Duration time, bool compilationSkipped,
+          [int pid = 0]) =>
+      VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);
 }
 
-class VmBatchCommand extends ProcessCommand implements VmCommand {
+class VMBatchCommand extends ProcessCommand implements VMCommand {
   final String dartFile;
   final bool checked;
 
-  VmBatchCommand._(String executable, String dartFile, List<String> arguments,
+  VMBatchCommand(String executable, String dartFile, List<String> arguments,
       Map<String, String> environmentOverrides,
       {this.checked = true, int index = 0})
       : dartFile = dartFile,
-        super._('vm-batch', executable, arguments, environmentOverrides, null,
+        super('vm-batch', executable, arguments, environmentOverrides, null,
             index);
 
-  VmBatchCommand indexedCopy(int index) =>
-      VmBatchCommand._(executable, dartFile, arguments, environmentOverrides,
+  VMBatchCommand indexedCopy(int index) =>
+      VMBatchCommand(executable, dartFile, arguments, environmentOverrides,
           checked: checked, index: index);
 
   @override
@@ -574,7 +526,7 @@
       checked ? ['--checked', dartFile] : [dartFile];
 
   @override
-  bool _equal(VmBatchCommand other) {
+  bool _equal(VMBatchCommand other) {
     return super._equal(other) &&
         dartFile == other.dartFile &&
         checked == other.checked;
@@ -602,7 +554,7 @@
   final bool useElf;
   final List<String> extraLibraries;
 
-  AdbPrecompilationCommand._(
+  AdbPrecompilationCommand(
       this.buildPath,
       this.processTestFilename,
       this.precompiledTestDirectory,
@@ -613,7 +565,7 @@
       {int index = 0})
       : super._("adb_precompilation", index: index);
 
-  AdbPrecompilationCommand indexedCopy(int index) => AdbPrecompilationCommand._(
+  AdbPrecompilationCommand indexedCopy(int index) => AdbPrecompilationCommand(
       buildPath,
       processTestFilename,
       precompiledTestDirectory,
@@ -622,6 +574,12 @@
       useElf,
       extraLibraries,
       index: index);
+
+  VMCommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+          List<int> stderr, Duration time, bool compilationSkipped,
+          [int pid = 0]) =>
+      VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);
+
   _buildHashCode(HashCodeBuilder builder) {
     super._buildHashCode(builder);
     builder.add(buildPath);
@@ -652,12 +610,12 @@
   final List<String> arguments;
   final List<String> extraLibraries;
 
-  AdbDartkCommand._(this.buildPath, this.processTestFilename, this.kernelFile,
+  AdbDartkCommand(this.buildPath, this.processTestFilename, this.kernelFile,
       this.arguments, this.extraLibraries,
       {int index = 0})
       : super._("adb_precompilation", index: index);
 
-  AdbDartkCommand indexedCopy(int index) => AdbDartkCommand._(
+  AdbDartkCommand indexedCopy(int index) => AdbDartkCommand(
       buildPath, processTestFilename, kernelFile, arguments, extraLibraries,
       index: index);
   _buildHashCode(HashCodeBuilder builder) {
@@ -679,15 +637,25 @@
       'to an attached device. Uses (and requires) adb.';
 }
 
-class JSCommandlineCommand extends ProcessCommand {
-  JSCommandlineCommand._(
+class JSCommandLineCommand extends ProcessCommand {
+  JSCommandLineCommand(
       String displayName, String executable, List<String> arguments,
       [Map<String, String> environmentOverrides, int index = 0])
-      : super._(displayName, executable, arguments, environmentOverrides, null,
+      : super(displayName, executable, arguments, environmentOverrides, null,
             index);
 
-  JSCommandlineCommand indexedCopy(int index) => JSCommandlineCommand._(
+  JSCommandLineCommand indexedCopy(int index) => JSCommandLineCommand(
       displayName, executable, arguments, environmentOverrides, index);
+
+  JSCommandLineOutput createOutput(
+          int exitCode,
+          bool timedOut,
+          List<int> stdout,
+          List<int> stderr,
+          Duration time,
+          bool compilationSkipped,
+          [int pid = 0]) =>
+      JSCommandLineOutput(this, exitCode, timedOut, stdout, stderr, time);
 }
 
 /// [ScriptCommand]s are executed by dart code.
@@ -697,97 +665,3 @@
 
   Future<ScriptCommandOutput> run();
 }
-
-class CleanDirectoryCopyCommand extends ScriptCommand {
-  final String _sourceDirectory;
-  final String _destinationDirectory;
-
-  CleanDirectoryCopyCommand._(this._sourceDirectory, this._destinationDirectory,
-      {int index = 0})
-      : super._('dir_copy', index: index);
-
-  CleanDirectoryCopyCommand indexedCopy(int index) =>
-      CleanDirectoryCopyCommand._(_sourceDirectory, _destinationDirectory,
-          index: index);
-
-  String get reproductionCommand =>
-      "Copying '$_sourceDirectory' to '$_destinationDirectory'.";
-
-  Future<ScriptCommandOutput> run() {
-    var watch = Stopwatch()..start();
-
-    var destination = io.Directory(_destinationDirectory);
-
-    return destination.exists().then((bool exists) {
-      Future cleanDirectoryFuture;
-      if (exists) {
-        cleanDirectoryFuture = TestUtils.deleteDirectory(_destinationDirectory);
-      } else {
-        cleanDirectoryFuture = Future.value(null);
-      }
-      return cleanDirectoryFuture.then((_) {
-        return TestUtils.copyDirectory(_sourceDirectory, _destinationDirectory);
-      });
-    }).then((_) {
-      return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
-    }).catchError((error) {
-      return ScriptCommandOutput(
-          this, Expectation.fail, "An error occured: $error.", watch.elapsed);
-    });
-  }
-
-  void _buildHashCode(HashCodeBuilder builder) {
-    super._buildHashCode(builder);
-    builder.addJson(_sourceDirectory);
-    builder.addJson(_destinationDirectory);
-  }
-
-  bool _equal(CleanDirectoryCopyCommand other) =>
-      super._equal(other) &&
-      _sourceDirectory == other._sourceDirectory &&
-      _destinationDirectory == other._destinationDirectory;
-}
-
-/// Makes a symbolic link to another directory.
-class MakeSymlinkCommand extends ScriptCommand {
-  final String _link;
-  final String _target;
-
-  MakeSymlinkCommand._(this._link, this._target, {int index = 0})
-      : super._('make_symlink', index: index);
-
-  MakeSymlinkCommand indexedCopy(int index) =>
-      MakeSymlinkCommand._(_link, _target, index: index);
-
-  String get reproductionCommand =>
-      "Make symbolic link '$_link' (target: $_target)'.";
-
-  Future<ScriptCommandOutput> run() {
-    var watch = Stopwatch()..start();
-    var targetFile = io.Directory(_target);
-    return targetFile.exists().then((bool targetExists) {
-      if (!targetExists) {
-        throw Exception("Target '$_target' does not exist");
-      }
-      var link = io.Link(_link);
-
-      return link.exists().then((bool exists) {
-        if (exists) link.deleteSync();
-      }).then((_) => link.create(_target));
-    }).then((_) {
-      return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
-    }).catchError((error) {
-      return ScriptCommandOutput(
-          this, Expectation.fail, "An error occured: $error.", watch.elapsed);
-    });
-  }
-
-  void _buildHashCode(HashCodeBuilder builder) {
-    super._buildHashCode(builder);
-    builder.addJson(_link);
-    builder.addJson(_target);
-  }
-
-  bool _equal(MakeSymlinkCommand other) =>
-      super._equal(other) && _link == other._link && _target == other._target;
-}
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 9e6d963..98f5983 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -8,7 +8,7 @@
 import 'dart:io' as io;
 
 import 'package:status_file/expectation.dart';
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
 
 import 'browser_controller.dart';
 import 'command.dart';
@@ -494,17 +494,6 @@
       : super(command, exitCode, timedOut, stdout, stderr, time,
             compilationSkipped, 0);
 
-  @override
-  void describe(TestCase testCase, Progress progress, OutputWriter output) {
-    if (testCase.testFile.isStaticErrorTest) {
-      _validateExpectedErrors(testCase, output);
-    }
-
-    if (!testCase.testFile.isStaticErrorTest || progress == Progress.verbose) {
-      super.describe(testCase, progress, output);
-    }
-  }
-
   Expectation result(TestCase testCase) {
     // TODO(kustermann): If we run the analyzer not in batch mode, make sure
     // that command.exitCodes matches 2 (errors), 1 (warnings), 0 (no warnings,
@@ -1097,50 +1086,6 @@
   }
 }
 
-CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut,
-    List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped,
-    [int pid = 0]) {
-  if (command is AnalysisCommand) {
-    return AnalysisCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is CompareAnalyzerCfeCommand) {
-    return CompareAnalyzerCfeCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is SpecParseCommand) {
-    return SpecParseCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is VmCommand) {
-    return VMCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, pid);
-  } else if (command is VMKernelCompilationCommand) {
-    return VMKernelCompilationCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is AdbPrecompilationCommand) {
-    return VMCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, pid);
-  } else if (command is FastaCompilationCommand) {
-    return FastaCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is CompilationCommand) {
-    if (command.displayName == 'precompiler' ||
-        command.displayName == 'app_jit') {
-      return VMCommandOutput(
-          command, exitCode, timedOut, stdout, stderr, time, pid);
-    } else if (command.displayName == 'dartdevc') {
-      return DevCompilerCommandOutput(command, exitCode, timedOut, stdout,
-          stderr, time, compilationSkipped, pid);
-    }
-    return CompilationCommandOutput(
-        command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
-  } else if (command is JSCommandlineCommand) {
-    return JSCommandLineOutput(
-        command, exitCode, timedOut, stdout, stderr, time);
-  }
-
-  return CommandOutput(command, exitCode, timedOut, stdout, stderr, time,
-      compilationSkipped, pid);
-}
-
 /// Mixin for outputs from a command that implement a Dart front end which
 /// reports static errors.
 mixin _StaticErrorOutput on CommandOutput {
@@ -1174,11 +1119,18 @@
 
   @override
   void describe(TestCase testCase, Progress progress, OutputWriter output) {
-    if (testCase.testFile.isStaticErrorTest) {
+    // Handle static error test output specially. We don't want to show the raw
+    // stdout if we can give the user the parsed expectations instead.
+    if (testCase.testFile.isStaticErrorTest && !hasCrashed && !hasTimedOut) {
       _validateExpectedErrors(testCase, output);
     }
 
-    if (!testCase.testFile.isStaticErrorTest || progress == Progress.verbose) {
+    // Don't show the "raw" output unless something strange happened or the
+    // user explicitly requests all the output.
+    if (hasTimedOut ||
+        hasCrashed ||
+        !testCase.testFile.isStaticErrorTest ||
+        progress == Progress.verbose) {
       super.describe(testCase, progress, output);
     }
   }
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 7a54fce..62629db 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -36,13 +36,13 @@
 
   bool get _isDebug => _configuration.mode.isDebug;
 
+  bool get _isProduct => _configuration.mode == Mode.product;
+
   bool get _isHostChecked => _configuration.isHostChecked;
 
   bool get _useSdk => _configuration.useSdk;
 
-  bool get _useEnableAsserts => _configuration.useEnableAsserts;
-
-  bool get previewDart2 => !_configuration.noPreviewDart2;
+  bool get _enableAsserts => _configuration.enableAsserts;
 
   /// Whether to run the runtime on the compilation result of a test which
   /// expects a compile-time error and the compiler did not emit one.
@@ -124,13 +124,12 @@
   }
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
-    return [...sharedOptions, ..._configuration.sharedOptions, ...args];
+      TestFile testFile, List<String> vmOptions, List<String> args) {
+    return [
+      ...testFile.sharedOptions,
+      ..._configuration.sharedOptions,
+      ...args
+    ];
   }
 
   List<String> computeRuntimeArguments(
@@ -157,11 +156,7 @@
       List<String> originalArguments,
       CommandArtifact artifact) {
     return [
-      if (_isDebug)
-        // Temporarily disable background compilation to avoid flaky crashes
-        // (see http://dartbug.com/30016 for details).
-        '--no-background-compilation',
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       if (_configuration.hotReload)
         '--hot-reload-test-mode'
       else if (_configuration.hotReloadRollback)
@@ -206,14 +201,9 @@
 
   @override
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     return [
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
       ...vmOptions,
       ...args
@@ -234,7 +224,7 @@
     }
 
     return [
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       if (_configuration.hotReload)
         '--hot-reload-test-mode'
       else if (_configuration.hotReloadRollback)
@@ -327,17 +317,12 @@
   }
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     // The result will be passed as an input to [extractArguments]
     // (i.e. the arguments to the [PipelineCommand]).
     return [
       ...vmOptions,
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
       ...args
     ];
@@ -394,7 +379,7 @@
     arguments = arguments.toList();
     arguments.add('--out=$outputFileName');
 
-    return Command.compilation(moniker, outputFileName, bootstrapDependencies(),
+    return CompilationCommand(moniker, outputFileName, bootstrapDependencies(),
         computeCompilerPath(), arguments, environmentOverrides,
         alwaysCompile: !_useSdk);
   }
@@ -417,16 +402,11 @@
       : super('dart2js', configuration);
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     return [
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
-      ...dart2jsOptions,
+      ...testFile.dart2jsOptions,
       ...args
     ];
   }
@@ -474,7 +454,7 @@
         uri.resolve('pkg/test_runner/lib/src/babel_transform.js').toFilePath();
     var babelStandalone =
         uri.resolve('third_party/babel/babel.min.js').toFilePath();
-    return Command.compilation(
+    return CompilationCommand(
         'babel',
         output,
         [],
@@ -498,16 +478,11 @@
   }
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     return [
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
-      ...ddcOptions,
+      ...testFile.ddcOptions,
       // The file being compiled is the last argument.
       args.last
     ];
@@ -581,7 +556,7 @@
 
     var inputDir = Path(inputFile).append("..").canonicalize().toNativePath();
     var displayName = useKernel ? 'dartdevk' : 'dartdevc';
-    return Command.compilation(displayName, outputFile, bootstrapDependencies(),
+    return CompilationCommand(displayName, outputFile, bootstrapDependencies(),
         computeCompilerPath(), args, environment,
         workingDirectory: inputDir);
   }
@@ -625,7 +600,7 @@
   int get timeoutMultiplier {
     var multiplier = 2;
     if (_isDebug) multiplier *= 4;
-    if (_useEnableAsserts) multiplier *= 2;
+    if (_enableAsserts) multiplier *= 2;
     return multiplier;
   }
 
@@ -675,7 +650,7 @@
       args = [tempKernelFile(tempDir)];
     }
 
-    return Command.compilation('remove_kernel_file', tempDir,
+    return CompilationCommand('remove_kernel_file', tempDir,
         bootstrapDependencies(), exec, args, environmentOverrides,
         alwaysCompile: !_useSdk);
   }
@@ -695,6 +670,8 @@
           // TestConfiguration.validate().
           assert(false);
         }
+      } else if (_configuration.builderTag == "crossword") {
+        exec = "${buildDir}_X64/gen_snapshot";
       } else {
         exec = "$buildDir/gen_snapshot";
       }
@@ -716,7 +693,7 @@
       ..._replaceDartFiles(arguments, tempKernelFile(tempDir))
     ];
 
-    return Command.compilation('precompiler', tempDir, bootstrapDependencies(),
+    return CompilationCommand('precompiler', tempDir, bootstrapDependencies(),
         exec, args, environmentOverrides,
         alwaysCompile: !_useSdk);
   }
@@ -778,7 +755,7 @@
       '$tempDir/out.S'
     ];
 
-    return Command.compilation('assemble', tempDir, bootstrapDependencies(), cc,
+    return CompilationCommand('assemble', tempDir, bootstrapDependencies(), cc,
         args, environmentOverrides,
         alwaysCompile: !_useSdk);
   }
@@ -792,7 +769,7 @@
   /// almost identical configurations are tested simultaneously.
   Command computeRemoveAssemblyCommand(String tempDir, List arguments,
       Map<String, String> environmentOverrides) {
-    return Command.compilation('remove_assembly', tempDir,
+    return CompilationCommand('remove_assembly', tempDir,
         bootstrapDependencies(), 'rm', ['$tempDir/out.S'], environmentOverrides,
         alwaysCompile: !_useSdk);
   }
@@ -807,18 +784,13 @@
   }
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> originalArguments) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     return [
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       ...filterVmOptions(vmOptions),
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
-      ...originalArguments
+      ...args
     ];
   }
 
@@ -838,7 +810,7 @@
         _replaceDartFiles(originalArguments, "$dir/out.aotsnapshot");
 
     return [
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
@@ -855,7 +827,7 @@
   int get timeoutMultiplier {
     var multiplier = 1;
     if (_isDebug) multiplier *= 2;
-    if (_useEnableAsserts) multiplier *= 2;
+    if (_enableAsserts) multiplier *= 2;
     return multiplier;
   }
 
@@ -871,7 +843,7 @@
   Command computeCompilationCommand(String tempDir, List<String> arguments,
       Map<String, String> environmentOverrides) {
     var snapshot = "$tempDir/out.jitsnapshot";
-    return Command.compilation(
+    return CompilationCommand(
         'app_jit',
         tempDir,
         bootstrapDependencies(),
@@ -882,19 +854,14 @@
   }
 
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> originalArguments) {
+      TestFile testFile, List<String> vmOptions, List<String> args) {
     return [
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       ...vmOptions,
-      ...sharedOptions,
+      ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
-      ...originalArguments,
-      ...dartOptions
+      ...args,
+      ...testFile.dartOptions
     ];
   }
 
@@ -905,7 +872,7 @@
       List<String> originalArguments,
       CommandArtifact artifact) {
     return [
-      if (_useEnableAsserts) '--enable_asserts',
+      if (_enableAsserts) '--enable_asserts',
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
@@ -941,10 +908,6 @@
 
   CommandArtifact computeCompilationArtifact(String tempDir,
       List<String> arguments, Map<String, String> environmentOverrides) {
-    if (!previewDart2) {
-      throw ArgumentError('--no-preview-dart-2 not supported');
-    }
-
     var args = [
       ...arguments,
       if (_configuration.useAnalyzerCfe) '--use-cfe',
@@ -953,7 +916,7 @@
 
     // Since this is not a real compilation, no artifacts are produced.
     return CommandArtifact(
-        [Command.analysis(computeCompilerPath(), args, environmentOverrides)],
+        [AnalysisCommand(computeCompilerPath(), args, environmentOverrides)],
         null,
         null);
   }
@@ -985,13 +948,9 @@
 
   CommandArtifact computeCompilationArtifact(String tempDir,
       List<String> arguments, Map<String, String> environmentOverrides) {
-    if (!previewDart2) {
-      throw ArgumentError('--no-preview-dart-2 not supported');
-    }
-
     // Since this is not a real compilation, no artifacts are produced.
     return CommandArtifact([
-      Command.compareAnalyzerCfe(
+      CompareAnalyzerCfeCommand(
           computeCompilerPath(), arguments.toList(), environmentOverrides)
     ], null, null);
   }
@@ -1019,7 +978,7 @@
 
     // Since this is not a real compilation, no artifacts are produced.
     return CommandArtifact([
-      Command.specParse(computeCompilerPath(), arguments, environmentOverrides)
+      SpecParseCommand(computeCompilerPath(), arguments, environmentOverrides)
     ], null, null);
   }
 
@@ -1041,9 +1000,11 @@
 
   bool get _useSdk;
 
+  bool get _isProduct;
+
   bool get _isAot;
 
-  bool get _useEnableAsserts;
+  bool get _enableAsserts;
 
   List<Uri> bootstrapDependencies();
 
@@ -1084,21 +1045,22 @@
           name.startsWith('--packages=') ||
           name.startsWith('--enable-experiment=')),
       '-Ddart.developer.causal_async_stacks=$causalAsyncStacks',
-      if (_useEnableAsserts ||
+      if (_enableAsserts ||
           arguments.contains('--enable-asserts') ||
           arguments.contains('--enable_asserts'))
         '--enable-asserts',
       if (_configuration.useKernelBytecode) ...[
         '--gen-bytecode',
         '--drop-ast',
-        '--bytecode-options=source-positions,local-var-info'
+        '--bytecode-options=source-positions${_isProduct ? '' : ',local-var-info,debugger-stops'}'
       ]
     ];
 
     var batchArgs = [if (useAbiVersion != null) useAbiVersion];
 
-    return Command.vmKernelCompilation(dillFile, true, bootstrapDependencies(),
-        genKernel, args, environmentOverrides, batchArgs);
+    return VMKernelCompilationCommand(dillFile, bootstrapDependencies(),
+        genKernel, args, environmentOverrides, batchArgs,
+        alwaysCompile: true);
   }
 }
 
@@ -1110,8 +1072,6 @@
 
   final Uri _vmExecutable;
 
-  bool get _isLegacy => _configuration.noPreviewDart2;
-
   factory FastaCompilerConfiguration(TestConfiguration configuration) {
     var buildDirectory =
         Uri.base.resolveUri(Uri.directory(configuration.buildDirectory));
@@ -1121,8 +1081,7 @@
       dillDir = buildDirectory.resolve("dart-sdk/lib/_internal/");
     }
 
-    var suffix = !configuration.noPreviewDart2 ? "_strong" : "";
-    var platformDill = dillDir.resolve("vm_platform$suffix.dill");
+    var platformDill = dillDir.resolve("vm_platform_strong.dill");
 
     var vmExecutable = buildDirectory
         .resolve(configuration.useSdk ? "dart-sdk/bin/dart" : "dart");
@@ -1149,7 +1108,6 @@
 
     var compilerArguments = [
       '--verify',
-      if (_isLegacy) "--legacy-mode",
       "-o",
       outputFileName,
       "--platform",
@@ -1158,26 +1116,24 @@
     ];
 
     return CommandArtifact([
-      Command.fasta(
+      FastaCompilationCommand(
           _compilerLocation,
-          output,
+          output.toFilePath(),
           bootstrapDependencies(),
-          _vmExecutable,
+          _vmExecutable.toFilePath(),
           compilerArguments,
           environmentOverrides,
-          Repository.uri)
+          Repository.uri.toFilePath())
     ], outputFileName, "application/x.dill");
   }
 
   @override
   List<String> computeCompilerArguments(
-      List<String> vmOptions,
-      List<String> sharedOptions,
-      List<String> dartOptions,
-      List<String> dart2jsOptions,
-      List<String> ddcOptions,
-      List<String> args) {
-    var arguments = [...sharedOptions, ..._configuration.sharedOptions];
+      TestFile testFile, List<String> vmOptions, List<String> args) {
+    var arguments = [
+      ...testFile.sharedOptions,
+      ..._configuration.sharedOptions
+    ];
     for (var argument in args) {
       if (argument == "--ignore-unrecognized-flags") continue;
       arguments.add(argument);
diff --git a/pkg/test_runner/lib/src/configuration.dart b/pkg/test_runner/lib/src/configuration.dart
index da4bfbc..47dfdae 100644
--- a/pkg/test_runner/lib/src/configuration.dart
+++ b/pkg/test_runner/lib/src/configuration.dart
@@ -104,6 +104,7 @@
   Mode get mode => configuration.mode;
   Runtime get runtime => configuration.runtime;
   System get system => configuration.system;
+  NnbdMode get nnbdMode => configuration.nnbdMode;
 
   // Boolean getters
   bool get hotReload => configuration.useHotReload;
@@ -112,13 +113,12 @@
   bool get isHostChecked => configuration.isHostChecked;
   bool get isCsp => configuration.isCsp;
   bool get isMinified => configuration.isMinified;
-  bool get noPreviewDart2 => !configuration.previewDart2;
   bool get useAnalyzerCfe => configuration.useAnalyzerCfe;
   bool get useAnalyzerFastaParser => configuration.useAnalyzerFastaParser;
   bool get useBlobs => configuration.useBlobs;
   bool get useElf => configuration.useElf;
   bool get useSdk => configuration.useSdk;
-  bool get useEnableAsserts => configuration.enableAsserts;
+  bool get enableAsserts => configuration.enableAsserts;
 
   // Various file paths.
 
@@ -149,6 +149,17 @@
   /// Extra VM options passed to the testing script.
   List<String> get vmOptions => configuration.vmOptions;
 
+  /// The names of the experiments to enable while running tests.
+  ///
+  /// A test may *require* an experiment to always be enabled by containing a
+  /// comment like:
+  ///
+  ///     // SharedOptions=--enable-experiment=extension-methods
+  ///
+  /// Enabling an experiment here in the configuration allows running the same
+  /// test both with an experiment on and off.
+  List<String> get experiments => configuration.experiments;
+
   /// Extra general options passed to the testing script.
   final List<String> sharedOptions;
 
@@ -244,7 +255,7 @@
 
     if (isMinified) args.add("--minify");
     if (isCsp) args.add("--csp");
-    if (useEnableAsserts) args.add("--enable-asserts");
+    if (enableAsserts) args.add("--enable-asserts");
     return args;
   }
 
@@ -438,42 +449,6 @@
 
     return normal;
   }
-
-  Map _summaryMap;
-
-  /// [toSummaryMap] returns a map of configurations important to the running
-  /// of a test. Flags and properties used for output are not included.
-  /// The summary map can be used to serialize to json for test-output logging.
-  Map toSummaryMap() {
-    return _summaryMap ??= {
-      'mode': mode.name,
-      'arch': architecture.name,
-      'compiler': compiler.name,
-      'runtime': runtime.name,
-      'checked': isChecked,
-      'host_checked': isHostChecked,
-      'minified': isMinified,
-      'csp': isCsp,
-      'system': system.name,
-      'vm_options': vmOptions,
-      'dart2js_options': dart2jsOptions,
-      'fasta': usesFasta,
-      'use_sdk': useSdk,
-      'builder_tag': builderTag,
-      'timeout': timeout,
-      'no_preview_dart_2': noPreviewDart2,
-      'use_cfe': useAnalyzerCfe,
-      'analyzer_use_fasta_parser': useAnalyzerFastaParser,
-      'enable_asserts': useEnableAsserts,
-      'hot_reload': hotReload,
-      'hot_reload_rollback': hotReloadRollback,
-      'batch': batch,
-      'batch_dart2js': batchDart2JS,
-      'reset_browser_configuration': resetBrowser,
-      'selectors': selectors.keys.toList(),
-      'use_kernel_bytecode': useKernelBytecode,
-    };
-  }
 }
 
 class Progress {
diff --git a/pkg/test_runner/lib/src/environment.dart b/pkg/test_runner/lib/src/environment.dart
index b028db0..f012f12 100644
--- a/pkg/test_runner/lib/src/environment.dart
+++ b/pkg/test_runner/lib/src/environment.dart
@@ -20,7 +20,7 @@
   "checked": _Variable.bool((c) => c.isChecked),
   "compiler": _Variable((c) => c.compiler.name, Compiler.names),
   "csp": _Variable.bool((c) => c.isCsp),
-  "enable_asserts": _Variable.bool((c) => c.useEnableAsserts),
+  "enable_asserts": _Variable.bool((c) => c.enableAsserts),
   "fasta": _Variable.bool((c) => c.usesFasta),
   "host_checked": _Variable.bool((c) => c.isHostChecked),
   "host_unchecked": _Variable.bool((c) => !c.isHostChecked),
@@ -30,11 +30,8 @@
   "jscl": _Variable.bool((c) => c.runtime.isJSCommandLine),
   "minified": _Variable.bool((c) => c.isMinified),
   "mode": _Variable((c) => c.mode.name, Mode.names),
-  "no_preview_dart_2": _Variable.bool((c) => c.noPreviewDart2),
-  "preview_dart_2": _Variable.bool((c) => !c.noPreviewDart2),
   "runtime": _Variable(_runtimeName, _runtimeNames),
   "spec_parser": _Variable.bool((c) => c.compiler == Compiler.specParser),
-  "strong": _Variable.bool((c) => !c.noPreviewDart2),
   "system": _Variable(_systemName, _systemNames),
   "use_sdk": _Variable.bool((c) => c.useSdk)
 };
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index c819037..9de4b81 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -164,9 +164,6 @@
         'Only run tests that are not marked `Slow` or `Timeout`.'),
     _Option.bool('enable_asserts',
         'Pass the --enable-asserts flag to dart2js or to the vm.'),
-    _Option.bool('no_preview_dart_2',
-        'Enable legacy Dart 1 behavior for some runtimes and compilers.',
-        hide: true),
     _Option.bool('use_cfe', 'Pass the --use-cfe flag to analyzer', hide: true),
     _Option.bool('analyzer_use_fasta_parser',
         'Pass the --use-fasta-parser flag to analyzer',
@@ -233,6 +230,9 @@
     _Option('chrome', 'Path to chrome browser executable.', hide: true),
     _Option('safari', 'Path to safari browser executable.', hide: true),
     _Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
+    _Option.bool('nnbd', '''Opt tests into non-nullable types.'''),
+    _Option.bool('nnbd_strong_checking',
+        '''Enable strong runtime checks of non-nullable types.'''),
     // TODO(rnystrom): This does not appear to be used. Remove?
     _Option('build_directory',
         'The name of the build directory, where products are placed.',
@@ -284,9 +284,9 @@
     _Option.int(
         'test_driver_error_port', 'Port for http test driver server errors.',
         defaultsTo: 0, hide: true),
-    _Option('test_list', 'File containing a list of tests to be executed',
+    _Option('test_list', 'File containing a list of tests to be executed.',
         hide: true),
-    _Option('tests', 'A newline separated list of tests to be executed'),
+    _Option('tests', 'A newline separated list of tests to be executed.'),
     _Option(
         'builder_tag',
         '''Machine specific options that is not captured by the regular test
@@ -297,6 +297,7 @@
     _Option('dart2js_options', 'Extra options for dart2js compilation step.',
         hide: true),
     _Option('shared_options', 'Extra shared options.', hide: true),
+    _Option('experiments', 'Experiment flags to enable.'),
     _Option(
         'babel',
         '''Transforms dart2js output with Babel. The value must be
@@ -380,9 +381,9 @@
       return null;
     }
     if (arguments.contains("--list-configurations")) {
-      final testMatrixFile = "tools/bots/test_matrix.json";
-      TestMatrix testMatrix = TestMatrix.fromPath(testMatrixFile);
-      for (final configuration in testMatrix.configurations
+      var testMatrixFile = "tools/bots/test_matrix.json";
+      var testMatrix = TestMatrix.fromPath(testMatrixFile);
+      for (var configuration in testMatrix.configurations
           .map((configuration) => configuration.name)
           .toList()
             ..sort()) {
@@ -390,10 +391,6 @@
       }
       return null;
     }
-    // Dart1 mode has been deprecated.
-    if (arguments.contains("--no-preview-dart-2")) {
-      return null;
-    }
 
     var configuration = <String, dynamic>{};
 
@@ -616,6 +613,7 @@
     var dart2jsOptions = listOption("dart2js_options");
     var vmOptions = listOption("vm_options");
     var sharedOptions = listOption("shared_options");
+    var experiments = listOption("experiments");
 
     // JSON reporting implies listing and reporting.
     if (data['report_in_json'] as bool) {
@@ -697,9 +695,9 @@
                     isMinified: data["minified"] as bool,
                     vmOptions: vmOptions,
                     dart2jsOptions: dart2jsOptions,
+                    experiments: experiments,
                     babel: data['babel'] as String,
-                    builderTag: data["builder_tag"] as String,
-                    previewDart2: true);
+                    builderTag: data["builder_tag"] as String);
             var configuration = TestConfiguration(
                 configuration: innerConfiguration,
                 progress: Progress.find(data["progress"] as String),
diff --git a/pkg/test_runner/lib/src/process_queue.dart b/pkg/test_runner/lib/src/process_queue.dart
index 8e660b0..72ab4c2 100644
--- a/pkg/test_runner/lib/src/process_queue.dart
+++ b/pkg/test_runner/lib/src/process_queue.dart
@@ -500,7 +500,7 @@
   Future cleanup();
   // TODO(kustermann): The [timeout] parameter should be a property of Command.
   Future<CommandOutput> runCommand(
-      Node<Command> node, covariant Command command, int timeout);
+      Node<Command> node, Command command, int timeout);
 }
 
 class CommandExecutorImpl implements CommandExecutor {
@@ -605,7 +605,7 @@
           adbDevicePool.releaseDevice(device);
         }
       });
-    } else if (command is VmBatchCommand) {
+    } else if (command is VMBatchCommand) {
       var name = command.displayName;
       return _getBatchRunner(command.displayName + command.dartFile)
           .runCommand(name, command, timeout, command.arguments);
@@ -713,7 +713,7 @@
       // immediately.
       if (result.exitCode != 0) break;
     }
-    return createCommandOutput(command, result.exitCode, result.timedOut,
+    return command.createOutput(result.exitCode, result.timedOut,
         utf8.encode('$writer'), [], stopwatch.elapsed, false);
   }
 
@@ -773,7 +773,7 @@
       // immediately.
       if (result.exitCode != 0) break;
     }
-    return createCommandOutput(command, result.exitCode, result.timedOut,
+    return command.createOutput(result.exitCode, result.timedOut,
         utf8.encode('$writer'), [], stopwatch.elapsed, false);
   }
 
@@ -1009,7 +1009,7 @@
     _arguments = arguments;
     _processEnvironmentOverrides = command.environmentOverrides;
 
-    // TOOD(jmesserly): this restarts `dartdevc --batch` to work around a
+    // TODO(jmesserly): this restarts `dartdevc --batch` to work around a
     // memory leak, see https://github.com/dart-lang/sdk/issues/30314.
     var clearMemoryLeak = command is CompilationCommand &&
         command.displayName == 'dartdevc' &&
@@ -1085,8 +1085,7 @@
     if (outcome == "CRASH") exitCode = unhandledCompilerExceptionExitCode;
     if (outcome == "PARSE_FAIL") exitCode = parseFailExitCode;
     if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
-    var output = createCommandOutput(
-        _command,
+    var output = _command.createOutput(
         exitCode,
         outcome == "TIMEOUT",
         _testStdout.toList(),
diff --git a/pkg/test_runner/lib/src/runtime_configuration.dart b/pkg/test_runner/lib/src/runtime_configuration.dart
index 9bcff67..04f4629 100644
--- a/pkg/test_runner/lib/src/runtime_configuration.dart
+++ b/pkg/test_runner/lib/src/runtime_configuration.dart
@@ -187,8 +187,7 @@
     // TODO(ahe): Avoid duplication of this method between d8 and jsshell.
     checkArtifact(artifact);
     return [
-      Command.jsCommandLine(
-          moniker, d8FileName, arguments, environmentOverrides)
+      JSCommandLineCommand(moniker, d8FileName, arguments, environmentOverrides)
     ];
   }
 
@@ -209,7 +208,7 @@
       bool isCrashExpected) {
     checkArtifact(artifact);
     return [
-      Command.jsCommandLine(
+      JSCommandLineCommand(
           moniker, jsShellFileName, arguments, environmentOverrides)
     ];
   }
@@ -282,7 +281,7 @@
     if (type == 'application/kernel-ir-fully-linked') {
       executable = dartVmExecutableFileName;
     }
-    return [Command.vm(executable, arguments, environmentOverrides)];
+    return [VMCommand(executable, arguments, environmentOverrides)];
   }
 }
 
@@ -306,7 +305,7 @@
     }
 
     return [
-      Command.vm(dartPrecompiledBinaryFileName, arguments, environmentOverrides)
+      VMCommand(dartPrecompiledBinaryFileName, arguments, environmentOverrides)
     ];
   }
 }
@@ -330,7 +329,7 @@
     final String buildPath = buildDir;
     final String processTest = processTestBinaryFileName;
     return [
-      Command.adbDartk(buildPath, processTest, script, arguments, extraLibs)
+      AdbDartkCommand(buildPath, processTest, script, arguments, extraLibs)
     ];
   }
 }
@@ -361,7 +360,7 @@
 
     String processTest = processTestBinaryFileName;
     return [
-      Command.adbPrecompiled(
+      AdbPrecompilationCommand(
           buildDir, processTest, script, arguments, useBlobs, useElf, extraLibs)
     ];
   }
@@ -391,7 +390,7 @@
       bool isCrashExpected) {
     String executable = dartVmBinaryFileName;
     return selfCheckers
-        .map((String tester) => Command.vmBatch(
+        .map((String tester) => VMBatchCommand(
             executable, tester, arguments, environmentOverrides,
             checked: _configuration.isChecked))
         .toList();
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
new file mode 100644
index 0000000..518d91b
--- /dev/null
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -0,0 +1,508 @@
+// 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.
+
+/// Describes a static error.
+///
+/// These can be parsed from comments in [TestFile]s, in which case they
+/// represent *expected* errors. If a test contains any of these, then it is a
+/// "static error test" and exists to validate that a conforming front end
+/// produces the expected compile-time errors.
+///
+/// Aside from location, there are two interesting attributes of an error that
+/// a test can verify: its error code and the error message. Currently, for
+/// analyzer we only care about the error code. The CFE does not report an
+/// error code and only reports a message. So this class takes advantage of
+/// that by allowing you to set expectations for analyzer and CFE independently
+/// by assuming the [code] field is only used for the former and the [message]
+/// for the latter.
+///
+/// This same class is also used for *reported* errors when parsing the output
+/// of a front end.
+class StaticError implements Comparable<StaticError> {
+  static const _unspecified = "unspecified";
+
+  /// Parses the set of static error expectations defined in the Dart source
+  /// file [source].
+  static List<StaticError> parseExpectations(String source) =>
+      _ErrorExpectationParser(source)._parse();
+
+  /// Collapses overlapping [errors] into a shorter list of errors where
+  /// possible.
+  ///
+  /// Two errors on the same location can be collapsed if one has an error code
+  /// but no message and the other has a message but no code.
+  static List<StaticError> simplify(List<StaticError> errors) {
+    var result = errors.toList();
+    result.sort();
+
+    for (var i = 0; i < result.length - 1; i++) {
+      var a = result[i];
+
+      // Look for a later error we can merge with this one. Usually, it will be
+      // adjacent to this one, but if there are multiple errors with no length
+      // on the same location, those will all be next to each other and their
+      // merge targets will come later. This happens when CFE reports multiple
+      // errors at the same location (messages but no length) and analyzer does
+      // too (codes and lengths but no messages).
+      for (var j = i + 1; j < result.length; j++) {
+        var b = result[j];
+
+        // Position must be the same. If the position is different, we can
+        // stop looking because all same-position errors will be adjacent.
+        if (a.line != b.line) break;
+        if (a.column != b.column) break;
+
+        // If they both have lengths that are different, we can't discard that
+        // information.
+        if (a.length != null && b.length != null && a.length != b.length) {
+          continue;
+        }
+
+        // Can't discard content.
+        if (a.code != null && b.code != null) continue;
+        if (a.message != null && b.message != null) continue;
+
+        result[i] = StaticError(
+            line: a.line,
+            column: a.column,
+            length: a.length ?? b.length,
+            code: a.code ?? b.code,
+            message: a.message ?? b.message);
+        result.removeAt(j);
+        break;
+      }
+    }
+
+    return result;
+  }
+
+  /// Determines whether all [actualErrors] match the given [expectedErrors].
+  ///
+  /// If they match, returns `null`. Otherwise returns a string describing the
+  /// mismatches. This for a human-friendly explanation of the difference
+  /// between the two sets of errors, while also being simple to implement.
+  /// An expected error that is completely identical to an actual error is
+  /// treated as a match. Everything else is a failure.
+  ///
+  /// It treats line number as the "identity" of an error. So if there are two
+  /// errors on the same line that differ in other properties, it reports that
+  /// as a "wrong" error. Any expected error on a line containing no actual
+  /// error is reported as a "missing" error. Conversely, an actual error on a
+  /// line containing no expected error is an "unexpected" error.
+  ///
+  /// By not treating the error's index in the list to be its identity, we
+  /// gracefully handle extra or missing errors without causing cascading
+  /// failures for later errors in the lists.
+  static String validateExpectations(Iterable<StaticError> expectedErrors,
+      Iterable<StaticError> actualErrors) {
+    // Don't require the test or front end to output in any specific order.
+    var sortedExpected = expectedErrors.toList();
+    var sortedActual = actualErrors.toList();
+    sortedExpected.sort();
+    sortedActual.sort();
+
+    var buffer = StringBuffer();
+
+    describeError(String adjective, StaticError error, String verb) {
+      buffer.writeln("$adjective static error at ${error.location}:");
+      if (error.code == _unspecified) {
+        buffer.writeln("- $verb unspecified error code.");
+      } else if (error.code != null) {
+        buffer.writeln("- $verb error code ${error.code}.");
+      }
+
+      if (error.message == _unspecified) {
+        buffer.writeln("- $verb unspecified error message.");
+      } else if (error.message != null) {
+        buffer.writeln("- $verb error message '${error.message}'.");
+      }
+      buffer.writeln();
+    }
+
+    var expectedIndex = 0;
+    var actualIndex = 0;
+    for (;
+        expectedIndex < sortedExpected.length &&
+            actualIndex < sortedActual.length;) {
+      var expected = sortedExpected[expectedIndex];
+      var actual = sortedActual[actualIndex];
+      var differences = expected.describeDifferences(actual);
+      if (differences == null) {
+        expectedIndex++;
+        actualIndex++;
+        continue;
+      }
+
+      if (expected.line == actual.line) {
+        buffer.writeln("Wrong static error at ${expected.location}:");
+        for (var difference in differences) {
+          buffer.writeln("- $difference");
+        }
+        buffer.writeln();
+        expectedIndex++;
+        actualIndex++;
+      } else if (expected.line < actual.line) {
+        describeError("Missing", expected, "Expected");
+        expectedIndex++;
+      } else {
+        describeError("Unexpected", actual, "Had");
+        actualIndex++;
+      }
+    }
+
+    // Output any trailing expected or actual errors if the lengths of the
+    // lists differ.
+    for (; expectedIndex < sortedExpected.length; expectedIndex++) {
+      describeError("Missing", sortedExpected[expectedIndex], "Expected");
+    }
+
+    for (; actualIndex < sortedActual.length; actualIndex++) {
+      describeError("Unexpected", sortedActual[actualIndex], "Had");
+    }
+
+    if (buffer.isEmpty) return null;
+    return buffer.toString().trimRight();
+  }
+
+  /// The one-based line number of the beginning of the error's location.
+  final int line;
+
+  /// The one-based column number of the beginning of the error's location.
+  final int column;
+
+  /// The number of characters in the error location.
+  ///
+  /// This is optional. The CFE only reports error location, but not length.
+  final int length;
+
+  /// The expected analyzer error code for the error or `null` if this error
+  /// isn't expected to be reported by analyzer.
+  final String code;
+
+  /// The expected CFE error message or `null` if this error isn't expected to
+  /// be reported by the CFE.
+  final String message;
+
+  /// The zero-based index of the first line in the [TestFile] containing the
+  /// marker comments that define this error.
+  ///
+  /// If this error was not parsed from a file, this may be `null`.
+  final int markerStartLine;
+
+  /// The zero-based index of the last line in the [TestFile] containing the
+  /// marker comments that define this error, inclusive.
+  ///
+  /// If this error was not parsed from a file, this may be `null`.
+  final int markerEndLine;
+
+  /// Creates a new StaticError at the given location with the given expected
+  /// error code and message.
+  ///
+  /// In order to make it easier to incrementally add error tests before a
+  /// feature is fully implemented or specified, an error expectation can be in
+  /// an "unspecified" state for either or both platforms by having the error
+  /// code or message be the special string "unspecified". When an unspecified
+  /// error is tested, a front end is expected to report *some* error on that
+  /// error's line, but it can be any location, error code, or message.
+  StaticError(
+      {this.line,
+      this.column,
+      this.length,
+      this.code,
+      this.message,
+      this.markerStartLine,
+      this.markerEndLine}) {
+    // Must have a location.
+    assert(line != null);
+    assert(column != null);
+
+    // Must have at least one piece of description.
+    assert(code != null || message != null);
+  }
+
+  /// Whether this error should be reported by analyzer.
+  bool get isAnalyzer => code != null;
+
+  /// Whether this error should be reported by the CFE.
+  bool get isCfe => message != null;
+
+  /// A textual description of this error's location.
+  String get location {
+    var result = "line $line, column $column";
+    if (length != null) result += ", length $length";
+    return result;
+  }
+
+  String toString() {
+    var result = "Error at $location";
+    if (code != null) result += "\n$code";
+    if (message != null) result += "\n$message";
+    return result;
+  }
+
+  /// Orders errors primarily by location, then by other fields if needed.
+  @override
+  int compareTo(StaticError other) {
+    if (line != other.line) return line.compareTo(other.line);
+    if (column != other.column) return column.compareTo(other.column);
+
+    // Sort no length after all other lengths.
+    if (length == null && other.length != null) return 1;
+    if (length != null && other.length == null) return -1;
+    if (length != other.length) return length.compareTo(other.length);
+
+    var thisCode = code ?? "";
+    var otherCode = other.code ?? "";
+    if (thisCode != otherCode) return thisCode.compareTo(otherCode);
+
+    var thisMessage = message ?? "";
+    var otherMessage = other.message ?? "";
+    return thisMessage.compareTo(otherMessage);
+  }
+
+  /// Compares this error expectation to [actual].
+  ///
+  /// If this error correctly matches [actual], returns `null`. Otherwise
+  /// returns a list of strings describing the mismatch.
+  ///
+  /// Note that this does *not* check to see that [actual] matches the platforms
+  /// that this error expects. For example, if [actual] only reports an error
+  /// code (i.e. it is analyzer-only) and this error only specifies an error
+  /// message (i.e. it is CFE-only), this will still report differences in
+  /// location information. This method expects that error expectations have
+  /// already been filtered by platform so this will only be called in cases
+  /// where the platforms do match.
+  List<String> describeDifferences(StaticError actual) {
+    var differences = <String>[];
+
+    if (line != actual.line) {
+      differences.add("Expected on line $line but was on ${actual.line}.");
+    }
+
+    // If the error is unspecified on the front end being tested, the column
+    // and length can be any values.
+    var requirePreciseLocation = code != _unspecified && actual.isAnalyzer ||
+        message != _unspecified && actual.isCfe;
+    if (requirePreciseLocation) {
+      if (column != actual.column) {
+        differences
+            .add("Expected on column $column but was on ${actual.column}.");
+      }
+
+      // This error represents an expectation, so should have a length.
+      assert(length != null);
+      if (actual.length != null && length != actual.length) {
+        differences.add("Expected length $length but was ${actual.length}.");
+      }
+    }
+
+    if (code != null &&
+        code != _unspecified &&
+        actual.code != null &&
+        code != actual.code) {
+      differences.add("Expected error code $code but was ${actual.code}.");
+    }
+
+    if (message != null &&
+        message != _unspecified &&
+        actual.message != null &&
+        message != actual.message) {
+      differences.add(
+          "Expected error message '$message' but was '${actual.message}'.");
+    }
+
+    if (differences.isNotEmpty) return differences;
+    return null;
+  }
+}
+
+class _ErrorExpectationParser {
+  /// Marks the location of an expected error, like so:
+  ///
+  ///     int i = "s";
+  ///     //      ^^^
+  ///
+  /// We look for a line that starts with a line comment followed by spaces and
+  /// carets.
+  static final _caretLocationRegExp = RegExp(r"^\s*//\s*(\^+)\s*$");
+
+  /// Matches an explicit error location with a length, like:
+  ///
+  ///     // [error line 1, column 17, length 3]
+  static final _explicitLocationAndLengthRegExp =
+      RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*,\s*"
+          r"length\s+(\d+)\s*\]\s*$");
+
+  /// Matches an explicit error location without a length, like:
+  ///
+  ///     // [error line 1, column 17]
+  static final _explicitLocationRegExp =
+      RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*\]\s*$");
+
+  /// An analyzer error expectation starts with `// [analyzer]`.
+  static final _analyzerErrorRegExp = RegExp(r"^\s*// \[analyzer\]\s*(.*)");
+
+  /// An analyzer error code is a dotted identifier or the magic string
+  /// "unspecified".
+  static final _errorCodeRegExp = RegExp(r"^\w+\.\w+|unspecified$");
+
+  /// The first line of a CFE error expectation starts with `// [cfe]`.
+  static final _cfeErrorRegExp = RegExp(r"^\s*// \[cfe\]\s*(.*)");
+
+  /// Any line-comment-only lines after the first line of a CFE error message
+  /// are part of it.
+  static final _errorMessageRestRegExp = RegExp(r"^\s*//\s*(.*)");
+
+  /// Matches the multitest marker and yields the preceding content.
+  final _stripMultitestRegExp = RegExp(r"(.*)//#");
+
+  final List<String> _lines;
+  final List<StaticError> _errors = [];
+  int _currentLine = 0;
+
+  // One-based index of the last line that wasn't part of an error expectation.
+  int _lastRealLine = -1;
+
+  _ErrorExpectationParser(String source) : _lines = source.split("\n");
+
+  List<StaticError> _parse() {
+    while (!_isAtEnd) {
+      var sourceLine = _peek(0);
+
+      var match = _caretLocationRegExp.firstMatch(sourceLine);
+      if (match != null) {
+        if (_lastRealLine == -1) {
+          _fail("An error expectation must follow some code.");
+        }
+
+        _parseErrorDetails(
+            line: _lastRealLine,
+            column: sourceLine.indexOf("^") + 1,
+            length: match.group(1).length);
+        _advance();
+        continue;
+      }
+
+      match = _explicitLocationAndLengthRegExp.firstMatch(sourceLine);
+      if (match != null) {
+        _parseErrorDetails(
+            line: int.parse(match.group(1)),
+            column: int.parse(match.group(2)),
+            length: int.parse(match.group(3)));
+        _advance();
+        continue;
+      }
+
+      match = _explicitLocationRegExp.firstMatch(sourceLine);
+      if (match != null) {
+        _parseErrorDetails(
+            line: int.parse(match.group(1)), column: int.parse(match.group(2)));
+        _advance();
+        continue;
+      }
+
+      _lastRealLine = _currentLine + 1;
+      _advance();
+    }
+
+    return _errors;
+  }
+
+  /// Finishes parsing an error expectation after parsing the location.
+  void _parseErrorDetails({int line, int column, int length}) {
+    String code;
+    String message;
+
+    var startLine = _currentLine;
+
+    // Look for an error code line.
+    if (!_isAtEnd) {
+      var match = _analyzerErrorRegExp.firstMatch(_peek(1));
+      if (match != null) {
+        code = match.group(1);
+
+        if (!_errorCodeRegExp.hasMatch(code)) {
+          _fail("An analyzer error expectation should be a dotted identifier.");
+        }
+
+        _advance();
+      }
+    }
+
+    // Look for an error message.
+    if (!_isAtEnd) {
+      var match = _cfeErrorRegExp.firstMatch(_peek(1));
+      if (match != null) {
+        message = match.group(1);
+        _advance();
+
+        // Consume as many additional error message lines as we find.
+        while (!_isAtEnd) {
+          var nextLine = _peek(1);
+
+          // A location line shouldn't be treated as a message.
+          if (_caretLocationRegExp.hasMatch(nextLine)) break;
+          if (_explicitLocationAndLengthRegExp.hasMatch(nextLine)) break;
+          if (_explicitLocationRegExp.hasMatch(nextLine)) break;
+
+          // Don't let users arbitrarily order the error code and message.
+          if (_analyzerErrorRegExp.hasMatch(nextLine)) {
+            _fail("An analyzer expectation must come before a CFE "
+                "expectation.");
+          }
+
+          var messageMatch = _errorMessageRestRegExp.firstMatch(nextLine);
+          if (messageMatch == null) break;
+
+          message += "\n" + messageMatch.group(1);
+          _advance();
+        }
+      }
+    }
+
+    if (code == null && message == null) {
+      _fail("An error expectation must specify at least an analyzer or CFE "
+          "error.");
+    }
+
+    // Hack: If the error is CFE-only and the length is one, treat it as no
+    // length. The CFE does not output length information, and when the update
+    // tool writes a CFE-only error, it implicitly uses a length of one. Thus,
+    // when we parse back in a length one CFE error, we ignore the length so
+    // that the error round-trips correctly.
+    // TODO(rnystrom): Stop doing this when the CFE reports error lengths.
+    if (code == null && length == 1) length = null;
+
+    _errors.add(StaticError(
+        line: line,
+        column: column,
+        length: length,
+        code: code,
+        message: message,
+        markerStartLine: startLine,
+        markerEndLine: _currentLine));
+  }
+
+  bool get _isAtEnd => _currentLine >= _lines.length;
+
+  void _advance() {
+    _currentLine++;
+  }
+
+  String _peek(int offset) {
+    var line = _lines[_currentLine + offset];
+
+    // Strip off any multitest marker.
+    var multitestMatch = _stripMultitestRegExp.firstMatch(line);
+    if (multitestMatch != null) {
+      line = multitestMatch.group(1).trimRight();
+    }
+
+    return line;
+  }
+
+  void _fail(String message) {
+    throw FormatException("Test error on line ${_currentLine + 1}: $message");
+  }
+}
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index 131ae7b..4e7e080 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -384,8 +384,7 @@
         exitCode = nonUtfFakeExitCode;
       }
     }
-    var commandOutput = createCommandOutput(
-        command,
+    var commandOutput = command.createOutput(
         exitCode,
         timedOut,
         stdoutData,
diff --git a/pkg/test_runner/lib/src/test_file.dart b/pkg/test_runner/lib/src/test_file.dart
index d60e708..f24719a 100644
--- a/pkg/test_runner/lib/src/test_file.dart
+++ b/pkg/test_runner/lib/src/test_file.dart
@@ -4,6 +4,7 @@
 import 'dart:io';
 
 import 'path.dart';
+import 'static_error.dart';
 
 final _multiHtmlTestGroupRegExp = RegExp(r"\s*[^/]\s*group\('[^,']*");
 final _multiHtmlTestRegExp = RegExp(r"useHtmlIndividualConfiguration\(\)");
@@ -37,312 +38,6 @@
   return options;
 }
 
-/// Describes a static error.
-///
-/// These can be parsed from comments in [TestFile]s, in which case they
-/// represent *expected* errors. If a test contains any of these, then it is a
-/// "static error test" and exists to validate that a conforming front end
-/// produces the expected compile-time errors.
-///
-/// Aside from location, there are two interesting attributes of an error that
-/// a test can verify: its error code and the error message. Currently, for
-/// analyzer we only care about the error code. The CFE does not report an
-/// error code and only reports a message. So this class takes advantage of
-/// that by allowing you to set expectations for analyzer and CFE independently
-/// by assuming the [code] field is only used for the former and the [message]
-/// for the latter.
-///
-/// This same class is also used for *reported* errors when parsing the output
-/// of a front end.
-class StaticError implements Comparable<StaticError> {
-  static const _unspecified = "unspecified";
-
-  /// Collapses overlapping [errors] into a shorter list of errors where
-  /// possible.
-  ///
-  /// Two errors on the same location can be collapsed if one has an error code
-  /// but no message and the other has a message but no code.
-  static List<StaticError> simplify(List<StaticError> errors) {
-    var result = errors.toList();
-    result.sort();
-
-    for (var i = 0; i < result.length - 1; i++) {
-      var a = result[i];
-
-      // Look for a later error we can merge with this one. Usually, it will be
-      // adjacent to this one, but if there are multiple errors with no length
-      // on the same location, those will all be next to each other and their
-      // merge targets will come later. This happens when CFE reports multiple
-      // errors at the same location (messages but no length) and analyzer does
-      // too (codes and lengths but no messages).
-      for (var j = i + 1; j < result.length; j++) {
-        var b = result[j];
-
-        // Position must be the same. If the position is different, we can
-        // stop looking because all same-position errors will be adjacent.
-        if (a.line != b.line) break;
-        if (a.column != b.column) break;
-
-        // If they both have lengths that are different, we can't discard that
-        // information.
-        if (a.length != null && b.length != null && a.length != b.length) {
-          continue;
-        }
-
-        // Can't discard content.
-        if (a.code != null && b.code != null) continue;
-        if (a.message != null && b.message != null) continue;
-
-        result[i] = StaticError(
-            line: a.line,
-            column: a.column,
-            length: a.length ?? b.length,
-            code: a.code ?? b.code,
-            message: a.message ?? b.message);
-        result.removeAt(j);
-        break;
-      }
-    }
-
-    return result;
-  }
-
-  /// Determines whether all [actualErrors] match the given [expectedErrors].
-  ///
-  /// If they match, returns `null`. Otherwise returns a string describing the
-  /// mismatches. This for a human-friendly explanation of the difference
-  /// between the two sets of errors, while also being simple to implement.
-  /// An expected error that is completely identical to an actual error is
-  /// treated as a match. Everything else is a failure.
-  ///
-  /// It treats line number as the "identity" of an error. So if there are two
-  /// errors on the same line that differ in other properties, it reports that
-  /// as a "wrong" error. Any expected error on a line containing no actual
-  /// error is reported as a "missing" error. Conversely, an actual error on a
-  /// line containing no expected error is an "unexpected" error.
-  ///
-  /// By not treating the error's index in the list to be its identity, we
-  /// gracefully handle extra or missing errors without causing cascading
-  /// failures for later errors in the lists.
-  static String validateExpectations(Iterable<StaticError> expectedErrors,
-      Iterable<StaticError> actualErrors) {
-    // Don't require the test or front end to output in any specific order.
-    var sortedExpected = expectedErrors.toList();
-    var sortedActual = actualErrors.toList();
-    sortedExpected.sort();
-    sortedActual.sort();
-
-    var buffer = StringBuffer();
-
-    describeError(String adjective, StaticError error, String verb) {
-      buffer.writeln("$adjective static error at ${error.location}:");
-      if (error.code != null) {
-        buffer.writeln("- $verb error code ${error.code}.");
-      }
-
-      if (error.message != null) {
-        buffer.writeln("- $verb error message '${error.message}'.");
-      }
-      buffer.writeln();
-    }
-
-    var expectedIndex = 0;
-    var actualIndex = 0;
-    for (;
-        expectedIndex < sortedExpected.length &&
-            actualIndex < sortedActual.length;) {
-      var expected = sortedExpected[expectedIndex];
-      var actual = sortedActual[actualIndex];
-      var differences = expected.describeDifferences(actual);
-      if (differences == null) {
-        expectedIndex++;
-        actualIndex++;
-        continue;
-      }
-
-      if (expected.line == actual.line) {
-        buffer.writeln("Wrong static error at ${expected.location}:");
-        for (var difference in differences) {
-          buffer.writeln("- $difference");
-        }
-        buffer.writeln();
-        expectedIndex++;
-        actualIndex++;
-      } else if (expected.line < actual.line) {
-        describeError("Missing", expected, "Expected");
-        expectedIndex++;
-      } else {
-        describeError("Unexpected", actual, "Had");
-        actualIndex++;
-      }
-    }
-
-    // Output any trailing expected or actual errors if the lengths of the
-    // lists differ.
-    for (; expectedIndex < sortedExpected.length; expectedIndex++) {
-      describeError("Missing", sortedExpected[expectedIndex], "Expected");
-    }
-
-    for (; actualIndex < sortedActual.length; actualIndex++) {
-      describeError("Unexpected", sortedActual[actualIndex], "Had");
-    }
-
-    if (buffer.isEmpty) return null;
-    return buffer.toString().trimRight();
-  }
-
-  /// The one-based line number of the beginning of the error's location.
-  final int line;
-
-  /// The one-based column number of the beginning of the error's location.
-  final int column;
-
-  /// The number of characters in the error location.
-  ///
-  /// This is optional. The CFE only reports error location, but not length.
-  final int length;
-
-  /// The expected analyzer error code for the error or `null` if this error
-  /// isn't expected to be reported by analyzer.
-  final String code;
-
-  /// The expected CFE error message or `null` if this error isn't expected to
-  /// be reported by the CFE.
-  final String message;
-
-  /// The zero-based index of the first line in the [TestFile] containing the
-  /// marker comments that define this error.
-  ///
-  /// If this error was not parsed from a file, this may be `null`.
-  final int markerStartLine;
-
-  /// The zero-based index of the last line in the [TestFile] containing the
-  /// marker comments that define this error, inclusive.
-  ///
-  /// If this error was not parsed from a file, this may be `null`.
-  final int markerEndLine;
-
-  /// Creates a new StaticError at the given location with the given expected
-  /// error code and message.
-  ///
-  /// In order to make it easier to incrementally add error tests before a
-  /// feature is fully implemented or specified, an error expectation can be in
-  /// an "unspecified" state for either or both platforms by having the error
-  /// code or message be the special string "unspecified". When an unspecified
-  /// error is tested, a front end is expected to report *some* error on that
-  /// error's line, but it can be any location, error code, or message.
-  StaticError(
-      {this.line,
-      this.column,
-      this.length,
-      this.code,
-      this.message,
-      this.markerStartLine,
-      this.markerEndLine}) {
-    // Must have a location.
-    assert(line != null);
-    assert(column != null);
-
-    // Must have at least one piece of description.
-    assert(code != null || message != null);
-  }
-
-  /// Whether this error should be reported by analyzer.
-  bool get isAnalyzer => code != null;
-
-  /// Whether this error should be reported by the CFE.
-  bool get isCfe => message != null;
-
-  /// A textual description of this error's location.
-  String get location {
-    var result = "line $line, column $column";
-    if (length != null) result += ", length $length";
-    return result;
-  }
-
-  String toString() {
-    var result = "Error at $location";
-    if (code != null) result += "\n$code";
-    if (message != null) result += "\n$message";
-    return result;
-  }
-
-  /// Orders errors primarily by location, then by other fields if needed.
-  @override
-  int compareTo(StaticError other) {
-    if (line != other.line) return line.compareTo(other.line);
-    if (column != other.column) return column.compareTo(other.column);
-
-    // Sort no length after all other lengths.
-    if (length == null && other.length != null) return 1;
-    if (length != null && other.length == null) return -1;
-    if (length != other.length) return length.compareTo(other.length);
-
-    var thisCode = code ?? "";
-    var otherCode = other.code ?? "";
-    if (thisCode != otherCode) return thisCode.compareTo(otherCode);
-
-    var thisMessage = message ?? "";
-    var otherMessage = other.message ?? "";
-    return thisMessage.compareTo(otherMessage);
-  }
-
-  /// Compares this error expectation to [actual].
-  ///
-  /// If this error correctly matches [actual], returns `null`. Otherwise
-  /// returns a list of strings describing the mismatch.
-  ///
-  /// Note that this does *not* check to see that [actual] matches the platforms
-  /// that this error expects. For example, if [actual] only reports an error
-  /// code (i.e. it is analyzer-only) and this error only specifies an error
-  /// message (i.e. it is CFE-only), this will still report differences in
-  /// location information. This method expects that error expectations have
-  /// already been filtered by platform so this will only be called in cases
-  /// where the platforms do match.
-  List<String> describeDifferences(StaticError actual) {
-    var differences = <String>[];
-
-    if (line != actual.line) {
-      differences.add("Expected on line $line but was on ${actual.line}.");
-    }
-
-    // If the error is unspecified on the front end being tested, the column
-    // and length can be any values.
-    var requirePreciseLocation = code != _unspecified && actual.isAnalyzer ||
-        message != _unspecified && actual.isCfe;
-    if (requirePreciseLocation) {
-      if (column != actual.column) {
-        differences
-            .add("Expected on column $column but was on ${actual.column}.");
-      }
-
-      // This error represents an expectation, so should have a length.
-      assert(length != null);
-      if (actual.length != null && length != actual.length) {
-        differences.add("Expected length $length but was ${actual.length}.");
-      }
-    }
-
-    if (code != null &&
-        code != _unspecified &&
-        actual.code != null &&
-        code != actual.code) {
-      differences.add("Expected error code $code but was ${actual.code}.");
-    }
-
-    if (message != null &&
-        message != _unspecified &&
-        actual.message != null &&
-        message != actual.message) {
-      differences.add(
-          "Expected error message '$message' but was '${actual.message}'.");
-    }
-
-    if (differences.isNotEmpty) return differences;
-    return null;
-  }
-}
-
 abstract class _TestFileBase {
   /// The test suite directory containing this test.
   final Path _suiteDirectory;
@@ -579,7 +274,7 @@
 
     List<StaticError> errorExpectations;
     try {
-      errorExpectations = ErrorExpectationParser.parse(contents);
+      errorExpectations = StaticError.parseExpectations(contents);
     } on FormatException catch (error) {
       throw FormatException(
           "Invalid error expectation syntax in $filePath:\n$error");
@@ -685,7 +380,7 @@
           bool hasStaticWarning,
           bool hasSyntaxError}) =>
       _MultitestFile(
-          this, path, multitestKey, ErrorExpectationParser.parse(contents),
+          this, path, multitestKey, StaticError.parseExpectations(contents),
           hasCompileError: hasCompileError ?? false,
           hasRuntimeError: hasRuntimeError ?? false,
           hasStaticWarning: hasStaticWarning ?? false,
@@ -764,188 +459,3 @@
       throw UnsupportedError(
           "Can't derive a test from one already derived from a multitest.");
 }
-
-class ErrorExpectationParser {
-  static List<StaticError> parse(String source) =>
-      ErrorExpectationParser._(source)._parse();
-
-  /// Marks the location of an expected error, like so:
-  ///
-  ///     int i = "s";
-  ///     //      ^^^
-  ///
-  /// We look for a line that starts with a line comment followed by spaces and
-  /// carets.
-  static final _caretLocationRegExp = RegExp(r"^\s*//\s*(\^+)\s*$");
-
-  /// Matches an explicit error location with a length, like:
-  ///
-  ///     // [error line 1, column 17, length 3]
-  static final _explicitLocationAndLengthRegExp =
-      RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*,\s*"
-          r"length\s+(\d+)\s*\]\s*$");
-
-  /// Matches an explicit error location without a length, like:
-  ///
-  ///     // [error line 1, column 17]
-  static final _explicitLocationRegExp =
-      RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*\]\s*$");
-
-  /// An analyzer error expectation starts with `// [analyzer]`.
-  static final _analyzerErrorRegExp = RegExp(r"^\s*// \[analyzer\]\s*(.*)");
-
-  /// An analyzer error code is a dotted identifier or the magic string
-  /// "unspecified".
-  static final _errorCodeRegExp = RegExp(r"^\w+\.\w+|unspecified$");
-
-  /// The first line of a CFE error expectation starts with `// [cfe]`.
-  static final _cfeErrorRegExp = RegExp(r"^\s*// \[cfe\]\s*(.*)");
-
-  /// Any line-comment-only lines after the first line of a CFE error message
-  /// are part of it.
-  static final _errorMessageRestRegExp = RegExp(r"^\s*//\s*(.*)");
-
-  /// Matches the multitest marker and yields the preceding content.
-  final _stripMultitestRegExp = RegExp(r"(.*)//#");
-
-  final List<String> _lines;
-  final List<StaticError> _errors = [];
-  int _currentLine = 0;
-
-  // One-based index of the last line that wasn't part of an error expectation.
-  int _lastRealLine = -1;
-
-  ErrorExpectationParser._(String source) : _lines = source.split("\n");
-
-  List<StaticError> _parse() {
-    while (!_isAtEnd) {
-      var sourceLine = _peek(0);
-
-      var match = _caretLocationRegExp.firstMatch(sourceLine);
-      if (match != null) {
-        if (_lastRealLine == -1) {
-          _fail("An error expectation must follow some code.");
-        }
-
-        _parseErrorDetails(
-            line: _lastRealLine,
-            column: sourceLine.indexOf("^") + 1,
-            length: match.group(1).length);
-        _advance();
-        continue;
-      }
-
-      match = _explicitLocationAndLengthRegExp.firstMatch(sourceLine);
-      if (match != null) {
-        _parseErrorDetails(
-            line: int.parse(match.group(1)),
-            column: int.parse(match.group(2)),
-            length: int.parse(match.group(3)));
-        _advance();
-        continue;
-      }
-
-      match = _explicitLocationRegExp.firstMatch(sourceLine);
-      if (match != null) {
-        _parseErrorDetails(
-            line: int.parse(match.group(1)), column: int.parse(match.group(2)));
-        _advance();
-        continue;
-      }
-
-      _lastRealLine = _currentLine + 1;
-      _advance();
-    }
-
-    return _errors;
-  }
-
-  /// Finishes parsing an error expectation after parsing the location.
-  void _parseErrorDetails({int line, int column, int length}) {
-    String code;
-    String message;
-
-    var startLine = _currentLine;
-
-    // Look for an error code line.
-    if (!_isAtEnd) {
-      var match = _analyzerErrorRegExp.firstMatch(_peek(1));
-      if (match != null) {
-        code = match.group(1);
-
-        if (!_errorCodeRegExp.hasMatch(code)) {
-          _fail("An analyzer error expectation should be a dotted identifier.");
-        }
-
-        _advance();
-      }
-    }
-
-    // Look for an error message.
-    if (!_isAtEnd) {
-      var match = _cfeErrorRegExp.firstMatch(_peek(1));
-      if (match != null) {
-        message = match.group(1);
-        _advance();
-
-        // Consume as many additional error message lines as we find.
-        while (!_isAtEnd) {
-          var nextLine = _peek(1);
-
-          // A location line shouldn't be treated as a message.
-          if (_caretLocationRegExp.hasMatch(nextLine)) break;
-          if (_explicitLocationAndLengthRegExp.hasMatch(nextLine)) break;
-          if (_explicitLocationRegExp.hasMatch(nextLine)) break;
-
-          // Don't let users arbitrarily order the error code and message.
-          if (_analyzerErrorRegExp.hasMatch(nextLine)) {
-            _fail("An analyzer expectation must come before a CFE "
-                "expectation.");
-          }
-
-          var messageMatch = _errorMessageRestRegExp.firstMatch(nextLine);
-          if (messageMatch == null) break;
-
-          message += "\n" + messageMatch.group(1);
-          _advance();
-        }
-      }
-    }
-
-    if (code == null && message == null) {
-      _fail("An error expectation must specify at least an analyzer or CFE "
-          "error.");
-    }
-
-    _errors.add(StaticError(
-        line: line,
-        column: column,
-        length: length,
-        code: code,
-        message: message,
-        markerStartLine: startLine,
-        markerEndLine: _currentLine));
-  }
-
-  bool get _isAtEnd => _currentLine >= _lines.length;
-
-  void _advance() {
-    _currentLine++;
-  }
-
-  String _peek(int offset) {
-    var line = _lines[_currentLine + offset];
-
-    // Strip off any multitest marker.
-    var multitestMatch = _stripMultitestRegExp.firstMatch(line);
-    if (multitestMatch != null) {
-      line = multitestMatch.group(1).trimRight();
-    }
-
-    return line;
-  }
-
-  void _fail(String message) {
-    throw FormatException("Test error on line ${_currentLine + 1}: $message");
-  }
-}
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 71a5870..f2fb6c7 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -257,22 +257,20 @@
   /// pubspec checkouts ...).
   String createOutputDirectory(Path testPath) {
     var checked = configuration.isChecked ? '-checked' : '';
-    var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
     var minified = configuration.isMinified ? '-minified' : '';
     var sdk = configuration.useSdk ? '-sdk' : '';
     var dirName = "${configuration.compiler.name}-${configuration.runtime.name}"
-        "$checked$legacy$minified$sdk";
+        "$checked$minified$sdk";
     return createGeneratedTestDirectoryHelper("tests", dirName, testPath);
   }
 
   String createCompilationOutputDirectory(Path testPath) {
     var checked = configuration.isChecked ? '-checked' : '';
-    var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
     var minified = configuration.isMinified ? '-minified' : '';
     var csp = configuration.isCsp ? '-csp' : '';
     var sdk = configuration.useSdk ? '-sdk' : '';
     var dirName = "${configuration.compiler.name}"
-        "$checked$legacy$minified$csp$sdk";
+        "$checked$minified$csp$sdk";
     return createGeneratedTestDirectoryHelper(
         "compilations", dirName, testPath);
   }
@@ -334,7 +332,7 @@
       doTest = null;
       if (onDone != null) onDone();
     } catch (error, s) {
-      print("Fatal error occured: $error");
+      print("Fatal error occurred: $error");
       print(s);
       exit(1);
     }
@@ -362,23 +360,20 @@
         hasStaticWarning: false,
         hasCrash: testExpectation == Expectation.crash);
 
-    var args = configuration.standardOptions.toList();
-    if (configuration.compilerConfiguration.previewDart2) {
-      var filename = configuration.architecture == Architecture.x64
-          ? '$buildDir/gen/kernel-service.dart.snapshot'
-          : '$buildDir/gen/kernel_service.dill';
-      var dfePath = Path(filename).absolute.toNativePath();
+    var filename = configuration.architecture == Architecture.x64
+        ? '$buildDir/gen/kernel-service.dart.snapshot'
+        : '$buildDir/gen/kernel_service.dill';
+    var dfePath = Path(filename).absolute.toNativePath();
+    var args = [
+      if (expectations.contains(Expectation.crash)) '--suppress-core-dump',
       // '--dfe' has to be the first argument for run_vm_test to pick it up.
-      args.insert(0, '--dfe=$dfePath');
-      args.addAll(configuration.vmOptions);
-    }
-    if (expectations.contains(Expectation.crash)) {
-      args.insert(0, '--suppress-core-dump');
-    }
+      '--dfe=$dfePath',
+      ...configuration.standardOptions,
+      ...configuration.vmOptions,
+      test.name
+    ];
 
-    args.add(test.name);
-
-    var command = Command.process(
+    var command = ProcessCommand(
         'run_vm_unittest', targetRunnerPath, args, environmentOverrides);
     enqueueNewTestCase(testFile, fullName, [command], expectations);
   }
@@ -701,12 +696,7 @@
     String tempDir;
     if (compilerConfiguration.hasCompiler) {
       compileTimeArguments = compilerConfiguration.computeCompilerArguments(
-          vmOptions,
-          testFile.sharedOptions,
-          testFile.dartOptions,
-          testFile.dart2jsOptions,
-          testFile.ddcOptions,
-          args);
+          testFile, vmOptions, args);
       // Avoid doing this for analyzer.
       var path = testFile.path;
       if (vmOptionsVariant != 0) {
@@ -873,13 +863,8 @@
     };
     assert(supportedCompilers.contains(configuration.compiler));
 
-    var args = configuration.compilerConfiguration.computeCompilerArguments(
-        null,
-        testFile.sharedOptions,
-        null,
-        testFile.dart2jsOptions,
-        testFile.ddcOptions,
-        commonArguments);
+    var args = configuration.compilerConfiguration
+        .computeCompilerArguments(testFile, null, commonArguments);
     var compilation = configuration.compilerConfiguration
         .computeCompilationArtifact(outputDir, args, environmentOverrides);
     commands.addAll(compilation.commands);
diff --git a/pkg/test_runner/lib/src/testing_servers.dart b/pkg/test_runner/lib/src/testing_servers.dart
index 9831e6d..df7bf91 100644
--- a/pkg/test_runner/lib/src/testing_servers.dart
+++ b/pkg/test_runner/lib/src/testing_servers.dart
@@ -164,7 +164,7 @@
   }
 
   void _onError(e) {
-    DebugLogger.error('HttpServer: an error occured', e);
+    DebugLogger.error('HttpServer: an error occurred', e);
   }
 
   Future<DispatchingServer> _startHttpServer(String host,
diff --git a/pkg/test_runner/lib/src/update_errors.dart b/pkg/test_runner/lib/src/update_errors.dart
index 19d81e4..f0fa6e4 100644
--- a/pkg/test_runner/lib/src/update_errors.dart
+++ b/pkg/test_runner/lib/src/update_errors.dart
@@ -1,7 +1,7 @@
 // Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-import 'test_file.dart';
+import 'static_error.dart';
 
 /// Matches leading indentation in a string.
 final _indentationRegExp = RegExp(r"^(\s*)");
@@ -19,7 +19,7 @@
   removeAnalyzer ??= true;
   removeCfe ??= true;
 
-  var existingErrors = ErrorExpectationParser.parse(source);
+  var existingErrors = StaticError.parseExpectations(source);
   var lines = source.split("\n");
 
   // Keep track of the indentation on any existing expectation markers. If
@@ -67,12 +67,19 @@
   }
 
   var previousIndent = 0;
+  var codeLine = 1;
   var result = <String>[];
   for (var i = 0; i < lines.length; i++) {
     // Keep the code.
     if (lines[i] != null) {
       result.add(lines[i]);
       previousIndent = _countIndentation(lines[i]);
+
+      // Keep track of the resulting line number of the last line containing
+      // real code. We use this when outputting explicit line numbers instead
+      // the error's reported line to compensate for added or removed lines
+      // above the error.
+      codeLine = result.length;
     }
 
     // Add expectations for any errors reported on this line.
@@ -89,14 +96,15 @@
 
       var comment = (" " * indent) + "//";
 
-      // If the error can't fit in a line comment or doesn't have a length, use
-      // an explicit location.
-      if (error.length == null) {
-        result.add("$comment [error line ${error.line}, column "
-            "${error.column}]");
-      } else if (error.column <= 2) {
-        result.add("$comment [error line ${error.line}, column "
-            "${error.column}, length ${error.length}]");
+      // If the error can't fit in a line comment, use an explicit location.
+      if (error.column <= 2) {
+        if (error.length == null) {
+          result.add("$comment [error line $codeLine, column "
+              "${error.column}]");
+        } else {
+          result.add("$comment [error line $codeLine, column "
+              "${error.column}, length ${error.length}]");
+        }
       } else {
         var spacing = " " * (error.column - 1 - 2 - indent);
         // A CFE-only error may not have a length, so treat it as length 1.
diff --git a/pkg/test_runner/lib/src/utils.dart b/pkg/test_runner/lib/src/utils.dart
index 84482aa..197d995 100644
--- a/pkg/test_runner/lib/src/utils.dart
+++ b/pkg/test_runner/lib/src/utils.dart
@@ -432,12 +432,10 @@
         configuration.compiler == Compiler.dartkb ||
         configuration.compiler == Compiler.dartkp) {
       var checked = configuration.isChecked ? '-checked' : '';
-      var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
       var minified = configuration.isMinified ? '-minified' : '';
       var csp = configuration.isCsp ? '-csp' : '';
       var sdk = configuration.useSdk ? '-sdk' : '';
-      var dirName = "${configuration.compiler.name}"
-          "$checked$legacy$minified$csp$sdk";
+      var dirName = "${configuration.compiler.name}$checked$minified$csp$sdk";
       var generatedPath =
           configuration.buildDirectory + "/generated_compilations/$dirName";
       if (FileSystemEntity.isDirectorySync(generatedPath)) {
diff --git a/pkg/test_runner/test/skipping_dart2js_compilations_test.dart b/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
index f1b7df3..3d6fb75 100644
--- a/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
+++ b/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
@@ -151,7 +151,7 @@
     ..add(createFileScript)
     ..add(fileUtils.scriptOutputPath.toNativePath());
   var bootstrapDeps = [Uri.parse("file://${fileUtils.testSnapshotFilePath}")];
-  return Command.compilation('dart2js', fileUtils.testJsFilePath.toNativePath(),
+  return CompilationCommand('dart2js', fileUtils.testJsFilePath.toNativePath(),
       bootstrapDeps, executable, arguments, {},
       alwaysCompile: false);
 }
diff --git a/pkg/test_runner/test/static_error_test.dart b/pkg/test_runner/test/static_error_test.dart
index f607ee9..806e077 100644
--- a/pkg/test_runner/test/static_error_test.dart
+++ b/pkg/test_runner/test/static_error_test.dart
@@ -4,7 +4,7 @@
 
 import 'package:expect/expect.dart';
 
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
 
 void main() {
   testFlags();
@@ -512,6 +512,49 @@
 Missing static error at line 7, column 2, length 3:
 - Expected error code ERR.G.
 - Expected error message '7.'.""");
+
+  // Unspecified errors.
+  expectValidate([
+    // Missing.
+    StaticError(line: 1, column: 2, length: 3, code: "unspecified"),
+    StaticError(line: 2, column: 2, length: 3, message: "unspecified"),
+    StaticError(
+        line: 3,
+        column: 2,
+        length: 3,
+        code: "unspecified",
+        message: "unspecified"),
+
+    // Right.
+    StaticError(line: 4, column: 2, length: 3, code: "unspecified"),
+    StaticError(line: 5, column: 2, length: 3, message: "unspecified"),
+    StaticError(
+        line: 6,
+        column: 2,
+        length: 3,
+        code: "unspecified",
+        message: "unspecified"),
+  ], [
+    StaticError(line: 4, column: 2, length: 3, code: "ACT.UAL"),
+    StaticError(line: 5, column: 2, length: 3, message: "Actual."),
+    StaticError(
+        line: 6, column: 2, length: 3, code: "ACT.UAL", message: "Actual."),
+
+    // Unexpected.
+    StaticError(line: 7, column: 9, length: 3, code: "ACT.UAL"),
+  ], """
+Missing static error at line 1, column 2, length 3:
+- Expected unspecified error code.
+
+Missing static error at line 2, column 2, length 3:
+- Expected unspecified error message.
+
+Missing static error at line 3, column 2, length 3:
+- Expected unspecified error code.
+- Expected unspecified error message.
+
+Unexpected static error at line 7, column 9, length 3:
+- Had error code ACT.UAL.""");
 }
 
 void expectNoDifferences(StaticError expectedError, StaticError actualError) {
diff --git a/pkg/test_runner/test/test_file_test.dart b/pkg/test_runner/test/test_file_test.dart
index aea3887..b35c116 100644
--- a/pkg/test_runner/test/test_file_test.dart
+++ b/pkg/test_runner/test/test_file_test.dart
@@ -6,6 +6,7 @@
 import 'package:expect/expect.dart';
 
 import 'package:test_runner/src/path.dart';
+import 'package:test_runner/src/static_error.dart';
 import 'package:test_runner/src/test_file.dart';
 
 // Note: This test file validates how some of the special markers used by the
@@ -457,6 +458,22 @@
 /\/      ^^^
 /\/ [analyzer] Not error code.
 """);
+
+  // A CFE-only error with length one is treated as having no length.
+  expectParseErrorExpectations("""
+int i = "s";
+/\/      ^
+/\/ [cfe] Message.
+
+int j = "s";
+/\/      ^
+/\/ [analyzer] Error.BAD
+/\/ [cfe] Message.
+""", [
+    StaticError(line: 1, column: 9, length: null, message: "Message."),
+    StaticError(
+        line: 5, column: 9, length: 1, code: "Error.BAD", message: "Message."),
+  ]);
 }
 
 void testName() {
diff --git a/pkg/test_runner/test/test_runner_test.dart b/pkg/test_runner/test/test_runner_test.dart
index 385e73c..4123612 100644
--- a/pkg/test_runner/test/test_runner_test.dart
+++ b/pkg/test_runner/test/test_runner_test.dart
@@ -99,12 +99,12 @@
       String name, Iterable<Expectation> expectations) {
     var args = packageOptions();
     args.addAll([Platform.script.toFilePath(), name]);
-    var command = Command.process('custom', Platform.executable, args, {});
+    var command = ProcessCommand('custom', Platform.executable, args, {});
     return _makeTestCase(name, DEFAULT_TIMEOUT, command, expectations);
   }
 
   TestCase _makeCrashTestCase(String name, Iterable<Expectation> expectations) {
-    var crashCommand = Command.process(
+    var crashCommand = ProcessCommand(
         'custom_crash', getProcessTestFileName(), ["0", "0", "1", "1"], {});
     // The crash test sometimes times out. Run it with a large timeout
     // to help diagnose the delay.
diff --git a/pkg/test_runner/test/update_errors_test.dart b/pkg/test_runner/test/update_errors_test.dart
index 03f0cc3..9d07b9c 100644
--- a/pkg/test_runner/test/update_errors_test.dart
+++ b/pkg/test_runner/test/update_errors_test.dart
@@ -4,7 +4,7 @@
 
 import 'package:expect/expect.dart';
 
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
 import 'package:test_runner/src/update_errors.dart';
 
 // Note: This test file validates how some of the special markers used by the
@@ -192,12 +192,12 @@
 /\/ [cfe] Error.
 """);
 
-  // Uses an explicit error location if there's no length.
+  // Uses length one if there's no length.
   expectUpdate("""
 int i = "bad";
 """, errors: [StaticError(line: 1, column: 9, message: "Error.")], expected: """
 int i = "bad";
-/\/ [error line 1, column 9]
+/\/      ^
 /\/ [cfe] Error.
 """);
 
@@ -212,6 +212,29 @@
 /\/ [cfe] Error.
 """);
 
+  // Handles shifted line numbers in explicit error locations.
+  // Note that the reported line is line 6, but the output is line 3 to take
+  // into account the three removed lines.
+  expectUpdate("""
+main() {
+/\/ ^^
+/\/ [analyzer] ERROR.CODE
+/\/ [cfe] Error.
+}
+Error here;
+""", errors: [
+    StaticError(line: 6, column: 1, length: 5, code: "NEW.ERROR"),
+    StaticError(line: 6, column: 2, length: 3, message: "Error."),
+  ], expected: """
+main() {
+}
+Error here;
+/\/ [error line 3, column 1, length 5]
+/\/ [analyzer] NEW.ERROR
+/\/ [error line 3, column 2, length 3]
+/\/ [cfe] Error.
+""");
+
   // Inserts a blank line if a subsequent line comment would become part of the
   // error message.
   expectUpdate("""
@@ -246,6 +269,65 @@
 /\/      ^^^^^
 /\/ [cfe] Wrong 1.
 """);
+
+  regression();
+}
+
+void regression() {
+  // https://github.com/dart-lang/sdk/issues/37990.
+  expectUpdate(
+      """
+int get xx => 3;
+int get yy => 3;
+
+class A {
+  void test() {
+    xx = 1;
+/\/  ^^^^^^^^^^^^^^
+/\/ [cfe] unspecified
+/\/  ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+
+
+    yy(4);
+/\/  ^^^^^^^^^^^^^^
+/\/ [cfe] unspecified
+/\/  ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+
+  }
+}
+""",
+      removeAnalyzer: false,
+      errors: [
+        StaticError(
+            line: 6, column: 5, length: 14, message: "Setter not found: 'xx'."),
+        StaticError(
+            line: 16,
+            column: 7,
+            message: "The method 'call' isn't defined for the class 'int'.")
+      ],
+      expected: """
+int get xx => 3;
+int get yy => 3;
+
+class A {
+  void test() {
+    xx = 1;
+/\/  ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+/\/ [cfe] Setter not found: 'xx'.
+
+
+    yy(4);
+/\/  ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+/\/    ^
+/\/ [cfe] The method 'call' isn't defined for the class 'int'.
+
+  }
+}
+""");
 }
 
 void expectUpdate(String original,
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 46061c9..9fa7acb 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -11,6 +11,7 @@
 
 import 'package:test_runner/src/command_output.dart';
 import 'package:test_runner/src/path.dart';
+import 'package:test_runner/src/static_error.dart';
 import 'package:test_runner/src/test_file.dart';
 import 'package:test_runner/src/update_errors.dart';
 import 'package:test_runner/src/utils.dart';
diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart
index 1c0c748..8338073 100644
--- a/pkg/testing/lib/src/chain.dart
+++ b/pkg/testing/lib/src/chain.dart
@@ -111,7 +111,11 @@
 
   ExpectationSet get expectationSet => ExpectationSet.Default;
 
-  Future<Null> run(Chain suite, Set<String> selectors) async {
+  Future<Null> run(Chain suite, Set<String> selectors,
+      {int shards = 1, int shard = 0}) async {
+    assert(shards >= 1, "Invalid shards count: $shards");
+    assert(0 <= shard && shard < shards,
+        "Invalid shard index: $shard, not in range [0,$shards[.");
     List<String> partialSelectors = selectors
         .where((s) => s.endsWith('...'))
         .map((s) => s.substring(0, s.length - 3))
@@ -124,6 +128,15 @@
     }
     List<TestDescription> descriptions = await stream.toList();
     descriptions.sort();
+    if (shards > 1) {
+      List<TestDescription> shardDescriptions = [];
+      for (int index = 0; index < descriptions.length; index++) {
+        if (index % shards == shard) {
+          shardDescriptions.add(descriptions[index]);
+        }
+      }
+      descriptions = shardDescriptions;
+    }
     Map<TestDescription, Result> unexpectedResults =
         <TestDescription, Result>{};
     Map<TestDescription, Set<Expectation>> unexpectedOutcomes =
diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart
index 1d83c9b..d16cf30 100644
--- a/pkg/testing/lib/src/run.dart
+++ b/pkg/testing/lib/src/run.dart
@@ -55,7 +55,7 @@
 /// `testing.json` isn't located in the current working directory and is a path
 /// relative to [me] which defaults to `Platform.script`.
 Future<Null> runMe(List<String> arguments, CreateContext f,
-    [String configurationPath, Uri me]) {
+    {String configurationPath, Uri me, int shards = 1, int shard = 0}) {
   me ??= Platform.script;
   return withErrorHandling(() async {
     TestRoot testRoot = await computeTestRoot(configurationPath, me);
@@ -65,7 +65,8 @@
       if (me == suite.source) {
         print("Running suite ${suite.name}...");
         ChainContext context = await f(suite, cl.environment);
-        await context.run(suite, new Set<String>.from(cl.selectors));
+        await context.run(suite, new Set<String>.from(cl.selectors),
+            shards: shards, shard: shard);
       }
     }
   });
diff --git a/pkg/vm/lib/bytecode/assembler.dart b/pkg/vm/lib/bytecode/assembler.dart
index c287838..5926c77 100644
--- a/pkg/vm/lib/bytecode/assembler.dart
+++ b/pkg/vm/lib/bytecode/assembler.dart
@@ -5,6 +5,7 @@
 library vm.bytecode.assembler;
 
 import 'package:kernel/ast.dart' show TreeNode;
+import 'package:vm/bytecode/options.dart';
 
 import 'dbc.dart';
 import 'exceptions.dart' show ExceptionsTable;
@@ -56,10 +57,12 @@
   final ExceptionsTable exceptionsTable = new ExceptionsTable();
   final LocalVariableTable localVariableTable = new LocalVariableTable();
   final SourcePositions sourcePositions = new SourcePositions();
+  final bool _emitSourcePositions;
   bool isUnreachable = false;
   int currentSourcePosition = TreeNode.noOffset;
 
-  BytecodeAssembler();
+  BytecodeAssembler(BytecodeOptions options)
+      : _emitSourcePositions = options.emitSourcePositions;
 
   int get offset => bytecode.length;
 
@@ -74,11 +77,27 @@
   }
 
   void emitSourcePosition() {
-    if (currentSourcePosition != TreeNode.noOffset && !isUnreachable) {
+    if (_emitSourcePositions &&
+        !isUnreachable &&
+        currentSourcePosition != TreeNode.noOffset) {
       sourcePositions.add(offset, currentSourcePosition);
     }
   }
 
+  // TreeNode.noOffset (-1) source position on calls is used to mark synthetic
+  // calls without corresponding source position. Debugger uses the absence of
+  // source position to distinguish these calls and avoid stopping at them
+  // while single stepping.
+  void emitSourcePositionForCall() {
+    if (_emitSourcePositions && !isUnreachable) {
+      sourcePositions.add(
+          offset,
+          currentSourcePosition == TreeNode.noOffset
+              ? SourcePositions.syntheticCodeMarker
+              : currentSourcePosition);
+    }
+  }
+
   void emitYieldPointSourcePosition() {
     if (!isUnreachable) {
       sourcePositions.addYieldPoint(offset, currentSourcePosition);
@@ -371,32 +390,32 @@
   }
 
   void emitDirectCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kDirectCall, rd, rf);
   }
 
   void emitInterfaceCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kInterfaceCall, rd, rf);
   }
 
   void emitInstantiatedInterfaceCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kInstantiatedInterfaceCall, rd, rf);
   }
 
   void emitUncheckedClosureCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kUncheckedClosureCall, rd, rf);
   }
 
   void emitUncheckedInterfaceCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kUncheckedInterfaceCall, rd, rf);
   }
 
   void emitDynamicCall(int rd, int rf) {
-    emitSourcePosition();
+    emitSourcePositionForCall();
     _emitInstructionDF(Opcode.kDynamicCall, rd, rf);
   }
 
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index 6804895..eeee7fc 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -31,20 +31,6 @@
   Byte tag;
 }
 
-enum InvocationKind {
-  method, // x.foo(...) or foo(...)
-  getter, // x.foo
-  setter  // x.foo = ...
-}
-
-type ConstantICData extends ConstantPoolEntry {
-  Byte tag = 7;
-  Byte flags(invocationKindBit0, invocationKindBit1, isDynamic);
-             // Where invocationKind is index into InvocationKind.
-  PackedObject targetName;
-  ConstantIndex argDesc;
-}
-
 type ConstantStaticField extends ConstantPoolEntry {
   Byte tag = 9;
   PackedObject field;
@@ -120,6 +106,13 @@
   PackedObject staticReceiverType;
 }
 
+// Occupies 2 entries in the constant pool
+type ConstantDynamicCall extends ConstantPoolEntry {
+  Byte tag = 31;
+  PackedObject selectorName;
+  PackedObject argDesc;
+}
+
 */
 
 enum ConstantTag {
@@ -130,7 +123,7 @@
   kUnused4,
   kUnused5,
   kUnused6,
-  kICData,
+  kUnused6a,
   kUnused7,
   kStaticField,
   kInstanceField,
@@ -154,6 +147,7 @@
   kDirectCall,
   kInterfaceCall,
   kInstantiatedInterfaceCall,
+  kDynamicCall,
 }
 
 String constantTagToString(ConstantTag tag) =>
@@ -180,8 +174,6 @@
     switch (tag) {
       case ConstantTag.kInvalid:
         break;
-      case ConstantTag.kICData:
-        return new ConstantICData.read(reader);
       case ConstantTag.kStaticField:
         return new ConstantStaticField.read(reader);
       case ConstantTag.kInstanceField:
@@ -210,6 +202,8 @@
         return new ConstantInterfaceCall.read(reader);
       case ConstantTag.kInstantiatedInterfaceCall:
         return new ConstantInstantiatedInterfaceCall.read(reader);
+      case ConstantTag.kDynamicCall:
+        return new ConstantDynamicCall.read(reader);
       // Make analyzer happy.
       case ConstantTag.kUnused1:
       case ConstantTag.kUnused2:
@@ -217,6 +211,7 @@
       case ConstantTag.kUnused4:
       case ConstantTag.kUnused5:
       case ConstantTag.kUnused6:
+      case ConstantTag.kUnused6a:
       case ConstantTag.kUnused7:
       case ConstantTag.kUnused8:
       case ConstantTag.kUnused9:
@@ -232,67 +227,10 @@
   }
 }
 
-enum InvocationKind { method, getter, setter }
-
-String _invocationKindToString(InvocationKind kind) {
-  switch (kind) {
-    case InvocationKind.method:
-      return '';
-    case InvocationKind.getter:
-      return 'get ';
-    case InvocationKind.setter:
-      return 'set ';
-  }
-  throw 'Unexpected InvocationKind $kind';
-}
-
-class ConstantICData extends ConstantPoolEntry {
-  static const int invocationKindMask = 3;
-  static const int flagDynamic = 1 << 2;
-
-  final int _flags;
-  final ObjectHandle targetName;
-  final int argDescConstantIndex;
-
-  ConstantICData(InvocationKind invocationKind, this.targetName,
-      this.argDescConstantIndex, bool isDynamic)
-      : assert(invocationKind.index <= invocationKindMask),
-        _flags = invocationKind.index | (isDynamic ? flagDynamic : 0);
-
-  InvocationKind get invocationKind =>
-      InvocationKind.values[_flags & invocationKindMask];
-
-  bool get isDynamic => (_flags & flagDynamic) != 0;
-
-  @override
-  ConstantTag get tag => ConstantTag.kICData;
-
-  @override
-  void writeValue(BufferedWriter writer) {
-    writer.writeByte(_flags);
-    writer.writePackedObject(targetName);
-    writer.writePackedUInt30(argDescConstantIndex);
-  }
-
-  ConstantICData.read(BufferedReader reader)
-      : _flags = reader.readByte(),
-        targetName = reader.readPackedObject(),
-        argDescConstantIndex = reader.readPackedUInt30();
-
-  @override
-  String toString() => 'ICData '
-      '${isDynamic ? 'dynamic ' : ''}'
-      '${_invocationKindToString(invocationKind)}'
-      'target-name $targetName, arg-desc CP#$argDescConstantIndex';
-
-  // ConstantICData entries are created per call site and should not be merged,
-  // so ConstantICData class uses identity [hashCode] and [operator ==].
-
-  @override
-  int get hashCode => identityHashCode(this);
-
-  @override
-  bool operator ==(other) => identical(this, other);
+enum InvocationKind {
+  method, // x.foo(...) or foo(...)
+  getter, // x.foo
+  setter // x.foo = ...
 }
 
 class ConstantStaticField extends ConstantPoolEntry {
@@ -693,6 +631,41 @@
       this.staticReceiverType == other.staticReceiverType;
 }
 
+class ConstantDynamicCall extends ConstantPoolEntry {
+  final ObjectHandle selectorName;
+  final ObjectHandle argDesc;
+
+  ConstantDynamicCall(this.selectorName, this.argDesc);
+
+  // Reserve 1 extra slot for arguments descriptor, following selector slot.
+  int get numReservedEntries => 1;
+
+  @override
+  ConstantTag get tag => ConstantTag.kDynamicCall;
+
+  @override
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(selectorName);
+    writer.writePackedObject(argDesc);
+  }
+
+  ConstantDynamicCall.read(BufferedReader reader)
+      : selectorName = reader.readPackedObject(),
+        argDesc = reader.readPackedObject();
+
+  @override
+  String toString() => 'DynamicCall $selectorName, $argDesc';
+
+  @override
+  int get hashCode => _combineHashes(selectorName.hashCode, argDesc.hashCode);
+
+  @override
+  bool operator ==(other) =>
+      other is ConstantDynamicCall &&
+      this.selectorName == other.selectorName &&
+      this.argDesc == other.argDesc;
+}
+
 /// Reserved constant pool entry.
 class _ReservedConstantPoolEntry extends ConstantPoolEntry {
   const _ReservedConstantPoolEntry();
@@ -726,17 +699,6 @@
       _add(new ConstantObjectRef(objectTable.getArgDescHandleByArguments(args,
           hasReceiver: hasReceiver, isFactory: isFactory)));
 
-  int addICData(
-          InvocationKind invocationKind, Name targetName, int argDescCpIndex,
-          {bool isDynamic: false}) =>
-      _add(new ConstantICData(
-          invocationKind,
-          objectTable.getSelectorNameHandle(targetName,
-              isGetter: invocationKind == InvocationKind.getter,
-              isSetter: invocationKind == InvocationKind.setter),
-          argDescCpIndex,
-          isDynamic));
-
   int addDirectCall(
           InvocationKind invocationKind, Member target, ObjectHandle argDesc) =>
       _add(new ConstantDirectCall(
@@ -762,12 +724,18 @@
           argDesc,
           objectTable.getHandle(staticReceiverType)));
 
+  int addDynamicCall(
+          InvocationKind invocationKind, Name selector, ObjectHandle argDesc) =>
+      _add(new ConstantDynamicCall(
+          objectTable.getSelectorNameHandle(selector,
+              isGetter: invocationKind == InvocationKind.getter,
+              isSetter: invocationKind == InvocationKind.setter),
+          argDesc));
+
   int addInstanceCall(InvocationKind invocationKind, Member target,
           Name targetName, ObjectHandle argDesc) =>
       (target == null)
-          ? addICData(
-              invocationKind, targetName, _add(new ConstantObjectRef(argDesc)),
-              isDynamic: true)
+          ? addDynamicCall(invocationKind, targetName, argDesc)
           : addInterfaceCall(invocationKind, target, argDesc);
 
   int addStaticField(Field field) =>
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index f091eab..790b10b6 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -10,7 +10,7 @@
 /// Before bumping current bytecode version format, make sure that
 /// all users have switched to a VM which is able to consume new
 /// version of bytecode.
-const int currentBytecodeFormatVersion = 19;
+const int currentBytecodeFormatVersion = 20;
 
 enum Opcode {
   kUnusedOpcode000,
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index e3d72a2..a84a607 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -906,6 +906,7 @@
   static const int isAsyncFlag = 1 << 4;
   static const int isAsyncStarFlag = 1 << 5;
   static const int isSyncStarFlag = 1 << 6;
+  static const int isDebuggableFlag = 1 << 7;
 
   final int flags;
   final ObjectHandle parent;
@@ -1130,6 +1131,9 @@
   factory AnnotationsDeclaration.read(BufferedReader reader) {
     return new AnnotationsDeclaration(reader.readPackedObject());
   }
+
+  @override
+  String toString() => object.toString();
 }
 
 class _Section {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 5c7b744..cee493c 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -4,10 +4,6 @@
 
 library vm.bytecode.gen_bytecode;
 
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
-    show ConstantEvaluator, EvaluationEnvironment;
 import 'package:front_end/src/api_unstable/vm.dart'
     show
         CompilerContext,
@@ -26,8 +22,6 @@
 import 'package:kernel/type_algebra.dart'
     show Substitution, containsTypeVariable;
 import 'package:kernel/type_environment.dart' show TypeEnvironment;
-import 'package:kernel/vm/constants_native_effects.dart'
-    show VmConstantsBackend;
 import 'assembler.dart';
 import 'bytecode_serialization.dart' show StringTable;
 import 'constant_pool.dart';
@@ -56,7 +50,6 @@
 import 'recognized_methods.dart' show RecognizedMethods;
 import 'recursive_types_validator.dart' show IllegalRecursiveTypeException;
 import 'source_positions.dart' show LineStarts, SourcePositions;
-import '../constants_error_reporter.dart' show ForwardConstantEvaluationErrors;
 import '../metadata/bytecode.dart';
 
 import 'dart:convert' show utf8;
@@ -81,14 +74,10 @@
   hierarchy ??= new ClassHierarchy(component,
       onAmbiguousSupertypes: ignoreAmbiguousSupertypes);
   final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
-  final constantsBackend = new VmConstantsBackend(coreTypes);
-  final errorReporter = new ForwardConstantEvaluationErrors();
-  final constantEvaluator = new ConstantEvaluator(constantsBackend,
-      options.environmentDefines, typeEnvironment, errorReporter);
   libraries ??= component.libraries;
   try {
-    final bytecodeGenerator = new BytecodeGenerator(component, coreTypes,
-        hierarchy, typeEnvironment, constantEvaluator, options);
+    final bytecodeGenerator = new BytecodeGenerator(
+        component, coreTypes, hierarchy, typeEnvironment, options);
     for (var library in libraries) {
       bytecodeGenerator.visitLibrary(library);
     }
@@ -103,7 +92,6 @@
   final CoreTypes coreTypes;
   final ClassHierarchy hierarchy;
   final TypeEnvironment typeEnvironment;
-  final ConstantEvaluator constantEvaluator;
   final BytecodeOptions options;
   final BytecodeMetadataRepository metadata = new BytecodeMetadataRepository();
   final RecognizedMethods recognizedMethods;
@@ -145,7 +133,7 @@
   int maxSourcePosition;
 
   BytecodeGenerator(ast.Component component, this.coreTypes, this.hierarchy,
-      this.typeEnvironment, this.constantEvaluator, this.options)
+      this.typeEnvironment, this.options)
       : recognizedMethods = new RecognizedMethods(typeEnvironment),
         formatVersion = currentBytecodeFormatVersion,
         astUriToSource = component.uriToSource {
@@ -339,7 +327,7 @@
       flags |= ClassDeclaration.hasSourcePositionsFlag;
       position = library.fileOffset;
     }
-    Annotations annotations = getAnnotations(library.annotations);
+    Annotations annotations = getLibraryAnnotations(library);
     if (annotations.object != null) {
       flags |= ClassDeclaration.hasAnnotationsFlag;
       if (annotations.hasPragma) {
@@ -374,8 +362,7 @@
     if (nodes.isEmpty) {
       return const Annotations(null, false);
     }
-    List<Constant> constants = constantEvaluator.withNewEnvironment(
-        () => nodes.map(_evaluateConstantExpression).toList());
+    List<Constant> constants = nodes.map(_getConstant).toList();
     bool hasPragma = constants.any(_isPragma);
     if (!options.emitAnnotations) {
       if (hasPragma) {
@@ -410,8 +397,7 @@
       return const Annotations(null, false);
     }
 
-    List<Constant> functionConstants = constantEvaluator.withNewEnvironment(
-        () => functionNodes.map(_evaluateConstantExpression).toList());
+    List<Constant> functionConstants = functionNodes.map(_getConstant).toList();
     bool hasPragma = functionConstants.any(_isPragma);
     if (!options.emitAnnotations && !hasPragma) {
       return const Annotations(null, false);
@@ -423,8 +409,8 @@
     bytecodeComponent.annotations.add(functionDecl);
 
     for (final parameterNodes in parameterNodeLists) {
-      List<Constant> parameterConstants = constantEvaluator.withNewEnvironment(
-          () => parameterNodes.map(_evaluateConstantExpression).toList());
+      List<Constant> parameterConstants =
+          parameterNodes.map(_getConstant).toList();
       final parameterObject = objectTable
           .getHandle(new ListConstant(const DynamicType(), parameterConstants));
       final parameterDecl = new AnnotationsDeclaration(parameterObject);
@@ -434,12 +420,72 @@
     return new Annotations(functionDecl, hasPragma);
   }
 
+  // Insert annotations for library and its dependencies into the
+  // annotations section. Returns annotations for the library only.
+  // Bytecode reader will implicitly find library dependencies by reading
+  // an extra object after reading library annotations.
+  Annotations getLibraryAnnotations(Library library) {
+    Annotations annotations = getAnnotations(library.annotations);
+    final bool emitDependencies =
+        options.emitAnnotations && library.dependencies.isNotEmpty;
+    if (annotations.object == null && !emitDependencies) {
+      return annotations;
+    }
+
+    // We need to emit both annotations and dependencies objects, appending
+    // null if an object is missing.
+    if (annotations.object == null) {
+      final annotationsDecl = new AnnotationsDeclaration(null);
+      bytecodeComponent.annotations.add(annotationsDecl);
+      annotations = new Annotations(annotationsDecl, false);
+    }
+    if (!emitDependencies) {
+      bytecodeComponent.annotations.add(new AnnotationsDeclaration(null));
+      return annotations;
+    }
+
+    // Create a constant object representing library dependencies.
+    // These objects are used by dart:mirrors and vm-service implementation.
+    final deps = <Constant>[];
+    for (var dependency in library.dependencies) {
+      final prefix = dependency.name != null
+          ? StringConstant(dependency.name)
+          : NullConstant();
+      final showNames = dependency.combinators
+          .where((c) => c.isShow)
+          .expand((c) => c.names)
+          .map((name) => StringConstant(name))
+          .toList();
+      final hideNames = dependency.combinators
+          .where((c) => c.isHide)
+          .expand((c) => c.names)
+          .map((name) => StringConstant(name))
+          .toList();
+      final depAnnots = dependency.annotations.map(_getConstant).toList();
+      deps.add(ListConstant(const DynamicType(), <Constant>[
+        StringConstant(dependency.targetLibrary.importUri.toString()),
+        BoolConstant(dependency.isExport),
+        BoolConstant(dependency.isDeferred),
+        prefix,
+        ListConstant(const DynamicType(), showNames),
+        ListConstant(const DynamicType(), hideNames),
+        ListConstant(const DynamicType(), depAnnots),
+      ]));
+    }
+    final ObjectHandle dependenciesObject =
+        objectTable.getHandle(ListConstant(const DynamicType(), deps));
+    final dependenciesDecl = new AnnotationsDeclaration(dependenciesObject);
+    bytecodeComponent.annotations.add(dependenciesDecl);
+
+    return annotations;
+  }
+
   FieldDeclaration getFieldDeclaration(Field field, Code initializer) {
     int flags = 0;
     Constant value;
     if (_hasTrivialInitializer(field)) {
       if (field.initializer != null) {
-        value = _evaluateConstantExpression(field.initializer);
+        value = _getConstant(field.initializer);
       }
     } else {
       flags |= FieldDeclaration.hasInitializerFlag;
@@ -675,9 +721,11 @@
   }
 
   ParameterDeclaration getParameterDeclaration(VariableDeclaration variable) {
-    final name = objectTable.getNameHandle(null, variable.name);
-    final type = objectTable.getHandle(variable.type);
-    return new ParameterDeclaration(name, type);
+    final name = variable.name;
+    final lib = name.startsWith('_') ? enclosingMember.enclosingLibrary : null;
+    final nameHandle = objectTable.getNameHandle(lib, name);
+    final typeHandle = objectTable.getHandle(variable.type);
+    return new ParameterDeclaration(nameHandle, typeHandle);
   }
 
   List<int> getParameterFlags(FunctionNode function) {
@@ -935,9 +983,7 @@
       _dartFfiLibrary ??= libraryIndex.tryGetLibrary('dart:ffi');
 
   void _recordSourcePosition(int fileOffset) {
-    if (options.emitSourcePositions) {
-      asm.currentSourcePosition = fileOffset;
-    }
+    asm.currentSourcePosition = fileOffset;
     maxSourcePosition = math.max(maxSourcePosition, fileOffset);
   }
 
@@ -1029,23 +1075,24 @@
     }
   }
 
-  Constant _evaluateConstantExpression(Expression expr) {
+  Constant _getConstant(Expression expr) {
     if (expr is ConstantExpression) {
       return expr.constant;
     }
-    final constant = constantEvaluator.evaluate(expr);
-    if (constant is UnevaluatedConstant &&
-        constant.expression is InvalidExpression) {
-      // Compile-time error is already reported. Proceed with compilation
-      // in order to report errors in other constant expressions.
-      hasErrors = true;
-      return new NullConstant();
-    }
-    return constant;
+
+    // Literals outside of const expressions are not transformed by the
+    // constant transformer, but they need to be treated as constants here.
+    if (expr is BoolLiteral) return new BoolConstant(expr.value);
+    if (expr is DoubleLiteral) return new DoubleConstant(expr.value);
+    if (expr is IntLiteral) return new IntConstant(expr.value);
+    if (expr is NullLiteral) return new NullConstant();
+    if (expr is StringLiteral) return new StringConstant(expr.value);
+
+    throw 'Expected constant, got ${expr.runtimeType}';
   }
 
   void _genPushConstExpr(Expression expr) {
-    final constant = _evaluateConstantExpression(expr);
+    final constant = _getConstant(expr);
     if (constant is NullConstant) {
       asm.emitPushNull();
     } else if (constant is BoolConstant) {
@@ -1302,16 +1349,11 @@
     if (condition is BoolLiteral) {
       return condition.value;
     }
-    Constant constant;
     if (condition is ConstantExpression) {
-      constant = condition.constant;
-    } else if ((condition is StaticGet && condition.target.isConst) ||
-        (condition is StaticInvocation && condition.isConst) ||
-        (condition is VariableGet && condition.variable.isConst)) {
-      constant = _evaluateConstantExpression(condition);
-    }
-    if (constant is BoolConstant) {
-      return constant.value;
+      Constant constant = condition.constant;
+      if (constant is BoolConstant) {
+        return constant.value;
+      }
     }
     return null;
   }
@@ -1324,6 +1366,29 @@
       }
       return;
     }
+    if (condition is MethodInvocation &&
+        condition.name.name == '==' &&
+        (condition.receiver is NullLiteral ||
+            condition.arguments.positional.single is NullLiteral)) {
+      if (condition.receiver is NullLiteral) {
+        _generateNode(condition.arguments.positional.single);
+      } else {
+        _generateNode(condition.receiver);
+      }
+      if (options.emitDebuggerStops &&
+          condition.fileOffset != TreeNode.noOffset) {
+        final savedSourcePosition = asm.currentSourcePosition;
+        _recordSourcePosition(condition.fileOffset);
+        asm.emitDebugCheck();
+        asm.currentSourcePosition = savedSourcePosition;
+      }
+      if (value) {
+        asm.emitJumpIfNull(dest);
+      } else {
+        asm.emitJumpIfNotNull(dest);
+      }
+      return;
+    }
     bool negated = _genCondition(condition);
     if (value) {
       _genJumpIfTrue(negated, dest);
@@ -1336,7 +1401,7 @@
     if (param.initializer == null) {
       return cp.addObjectRef(null);
     }
-    final constant = _evaluateConstantExpression(param.initializer);
+    final constant = _getConstant(param.initializer);
     return cp.addObjectRef(constant);
   }
 
@@ -1415,7 +1480,6 @@
           new List<TypeParameter>.from(enclosingFunction.typeParameters);
       functionTypeParametersSet = functionTypeParameters.toSet();
     }
-    constantEvaluator.env = new EvaluationEnvironment();
     if (!hasCode) {
       return;
     }
@@ -1430,7 +1494,7 @@
     initializedFields = null; // Tracked for constructors only.
     nullableFields = const <ObjectHandle>[];
     cp = new ConstantPool(stringTable, objectTable);
-    asm = new BytecodeAssembler();
+    asm = new BytecodeAssembler(options);
     savedAssemblers = <BytecodeAssembler>[];
     currentLoopDepth = 0;
     savedMaxSourcePositions = <int>[];
@@ -1537,7 +1601,6 @@
     functionTypeParametersSet = null;
     instantiatorTypeArguments = null;
     locals = null;
-    constantEvaluator.env = null;
     labeledStatements = null;
     switchCases = null;
     tryCatches = null;
@@ -1603,7 +1666,6 @@
     } else {
       asm.emitEntry(locals.frameSize);
     }
-    asm.emitCheckStack(0);
 
     if (isClosure) {
       asm.emitPush(locals.closureVarIndexInFrame);
@@ -1611,6 +1673,10 @@
       asm.emitPopLocal(locals.contextVarIndexInFrame);
     }
 
+    // CheckStack must see a properly initialized context when stress-testing
+    // stack trace collection.
+    asm.emitCheckStack(0);
+
     if (locals.hasFunctionTypeArgsVar) {
       if (function.typeParameters.isNotEmpty) {
         assert(!(node is Procedure && node.isFactory));
@@ -2045,20 +2111,13 @@
 
   void _pushAssemblerState() {
     savedAssemblers.add(asm);
-    asm = new BytecodeAssembler();
+    asm = new BytecodeAssembler(options);
   }
 
   void _popAssemblerState() {
     asm = savedAssemblers.removeLast();
   }
 
-  void _evaluateDefaultParameterValue(VariableDeclaration param) {
-    if (param.initializer != null && param.initializer is! BasicLiteral) {
-      final constant = _evaluateConstantExpression(param.initializer);
-      param.initializer = new ConstantExpression(constant)..parent = param;
-    }
-  }
-
   int _genClosureBytecode(
       LocalFunction node, String name, FunctionNode function) {
     _pushAssemblerState();
@@ -2082,12 +2141,6 @@
     List<Label> savedYieldPoints = yieldPoints;
     yieldPoints = locals.isSyncYieldingFrame ? <Label>[] : null;
 
-    // Replace default values of optional parameters with constants,
-    // as default value expressions could use local const variables which
-    // are not available in bytecode.
-    function.positionalParameters.forEach(_evaluateDefaultParameterValue);
-    locals.sortedNamedParameters.forEach(_evaluateDefaultParameterValue);
-
     final int closureIndex = closures.length;
     final closure = getClosureDeclaration(node, function, name, closureIndex,
         savedIsClosure ? parentFunction : enclosingMember);
@@ -2102,11 +2155,14 @@
         parentFunction != null &&
         (parentFunction.dartAsyncMarker == AsyncMarker.Async ||
             parentFunction.dartAsyncMarker == AsyncMarker.AsyncStar)) {
+      final savedSourcePosition = asm.currentSourcePosition;
+      _recordSourcePosition(TreeNode.noOffset);
       _genLoadVar(locals.asyncStackTraceVar,
           currentContextLevel: locals.contextLevelAtEntry);
       _genDirectCall(
           setAsyncThreadStackTrace, objectTable.getArgDescHandle(1), 1);
       asm.emitDrop1();
+      asm.currentSourcePosition = savedSourcePosition;
     }
 
     Label continuationSwitchLabel;
@@ -2190,6 +2246,7 @@
         flags |= ClosureDeclaration.isSyncStarFlag;
         break;
       default:
+        flags |= ClosureDeclaration.isDebuggableFlag;
         break;
     }
 
@@ -2447,7 +2504,7 @@
   /// the last finally block.
   void _generateNonLocalControlTransfer(
       TreeNode from, TreeNode to, GenerateContinuation continuation) {
-    if (options.emitDebuggerStops) {
+    if (options.emitDebuggerStops && from.fileOffset != TreeNode.noOffset) {
       asm.emitDebugCheck(); // Before context is unwound.
     }
     List<TryFinally> tryFinallyBlocks = _getEnclosingTryFinallyBlocks(from, to);
@@ -3063,6 +3120,10 @@
       }
     }
     tryCatches[tryCatch].needsStackTrace = true;
+
+    if (options.emitDebuggerStops) {
+      asm.emitDebugCheck(); // Allow breakpoint on explicit rethrow statement.
+    }
     _genRethrow(tryCatch);
   }
 
@@ -3076,13 +3137,8 @@
         initializer is NullLiteral) {
       return true;
     }
-    Constant constValue;
-    if (initializer is ConstantExpression) {
-      constValue = initializer.constant;
-    } else if (field.isConst) {
-      constValue = _evaluateConstantExpression(initializer);
-    }
-    if (constValue is PrimitiveConstant) {
+    if (initializer is ConstantExpression &&
+        initializer.constant is PrimitiveConstant) {
       return true;
     }
     return false;
@@ -3158,6 +3214,10 @@
 
     final target = node.target;
     if (target is Field) {
+      if (options.emitDebuggerStops &&
+          _variableSetNeedsDebugCheck(node.value)) {
+        asm.emitDebugCheck();
+      }
       int cpIndex = cp.addStaticField(target);
       asm.emitStoreStaticTOS(cpIndex);
     } else {
@@ -3209,6 +3269,10 @@
   @override
   visitThrow(Throw node) {
     _generateNode(node.expression);
+
+    if (options.emitDebuggerStops) {
+      asm.emitDebugCheck();
+    }
     asm.emitThrow(0);
   }
 
@@ -3273,7 +3337,8 @@
       rhs is ConstantExpression ||
       rhs is StaticGet ||
       rhs is FunctionExpression ||
-      rhs is VariableGet;
+      rhs is VariableGet ||
+      rhs is AsExpression;
 
   void _genFutureNull() {
     asm.emitPushNull();
@@ -3413,6 +3478,7 @@
 
     // Front-end inserts implicit cast (type check) which ensures that
     // result of iterable expression is Iterable<dynamic>.
+    _recordSourcePosition(node.iterable.fileOffset);
     asm.emitInterfaceCall(
         cp.addInterfaceCall(InvocationKind.getter, iterableIterator,
             objectTable.getArgDescHandle(1)),
@@ -3454,6 +3520,7 @@
     _genJumpIfFalse(/* negated = */ false, done);
 
     _enterScope(node);
+    _recordSourcePosition(node.bodyOffset);
 
     _genPushContextIfCaptured(node.variable);
 
@@ -3569,6 +3636,10 @@
       _generateNode(expr);
       _genReturnTOS();
     } else {
+      if (options.emitDebuggerStops) {
+        // Stop on the return statement before executing finally blocks.
+        asm.emitDebugCheck();
+      }
       if (expr is BasicLiteral) {
         _addFinallyBlocks(tryFinallyBlocks, () {
           _generateNode(expr);
@@ -3617,15 +3688,18 @@
       if (switchCase.isDefault) {
         defaultLabel = caseLabel;
       } else {
-        for (var expr in switchCase.expressions) {
+        final savedSourcePosition = asm.currentSourcePosition;
+        for (int i = 0; i < switchCase.expressions.length; ++i) {
+          _recordSourcePosition(switchCase.expressionOffsets[i]);
           asm.emitPush(temp);
-          _genPushConstExpr(expr);
+          _genPushConstExpr(switchCase.expressions[i]);
           asm.emitInterfaceCall(
               cp.addInterfaceCall(
                   InvocationKind.method, coreTypes.objectEquals, equalsArgDesc),
               2);
           _genJumpIfTrue(/* negated = */ false, caseLabel);
         }
+        asm.currentSourcePosition = savedSourcePosition;
       }
     }
 
@@ -3786,7 +3860,9 @@
 
     bool hasCatchAll = false;
 
+    final savedSourcePosition = asm.currentSourcePosition;
     for (Catch catchClause in node.catches) {
+      _recordSourcePosition(catchClause.fileOffset);
       tryBlock.types.add(cp.addType(catchClause.guard));
 
       Label skipCatch;
@@ -3824,6 +3900,7 @@
         asm.bind(skipCatch);
       }
     }
+    asm.currentSourcePosition = savedSourcePosition;
 
     if (!hasCatchAll) {
       tryBlock.needsStackTrace = true;
@@ -3874,10 +3951,7 @@
 
   @override
   visitVariableDeclaration(VariableDeclaration node) {
-    if (node.isConst) {
-      final Constant constant = _evaluateConstantExpression(node.initializer);
-      constantEvaluator.env.addVariableValue(node, constant);
-    } else {
+    if (!node.isConst) {
       final bool isCaptured = locals.isCaptured(node);
       if (isCaptured) {
         _genPushContextForVariable(node);
@@ -3891,7 +3965,9 @@
         asm.emitPushNull();
       }
 
-      if (options.emitDebuggerStops) {
+      if (options.emitDebuggerStops &&
+          (node.initializer == null ||
+              _variableSetNeedsDebugCheck(node.initializer))) {
         final savedSourcePosition = asm.currentSourcePosition;
         if (node.fileEqualsOffset != TreeNode.noOffset) {
           _recordSourcePosition(node.fileEqualsOffset);
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index d2d32f0..4176254 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -390,6 +390,13 @@
         _useVariable(_currentFrame.parent
             .getSyntheticVar(ContinuationVariables.awaitContextVar));
 
+        // Debugger looks for :controller_stream variable among captured
+        // variables in a context, so make sure to capture it.
+        if (_currentFrame.parent.dartAsyncMarker == AsyncMarker.AsyncStar) {
+          _useVariable(_currentFrame.parent
+              .getSyntheticVar(ContinuationVariables.controllerStreamVar));
+        }
+
         if (locals.options.causalAsyncStacks &&
             (_currentFrame.parent.dartAsyncMarker == AsyncMarker.Async ||
                 _currentFrame.parent.dartAsyncMarker ==
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
index 688f437..9b35141 100644
--- a/pkg/vm/lib/bytecode/object_table.dart
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -6,6 +6,7 @@
 
 import 'package:kernel/ast.dart' hide MapEntry;
 import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/type_algebra.dart' show getFreshTypeParameters;
 
 import 'bytecode_serialization.dart'
     show
@@ -2059,8 +2060,27 @@
         .getOrAddObject(new _TypeParameterHandle(parentHandle, indexInParent));
   }
 
+  /// This is a workaround to <https://github.com/dart-lang/sdk/issues/37536>.
+  /// TODO(37536): remove this workaround once the issue is fixed.
+  ///
+  /// In certain cases, front-end produces function types with type parameters
+  /// which already belong to a closure. This results in the incorrect
+  /// canonicalization of types.
+  ///
+  /// This method corrects FunctionType by creating fresh type parameters.
+  FunctionType _fixTypeParameters(FunctionType type) {
+    for (var typeParam in type.typeParameters) {
+      if (typeParam.parent != null) {
+        final fresh = getFreshTypeParameters(type.typeParameters);
+        return fresh.applyToFunctionType(type);
+      }
+    }
+    return type;
+  }
+
   @override
   ObjectHandle visitFunctionType(FunctionType node) {
+    node = _fixTypeParameters(node);
     final int numEnclosingTypeParameters = _typeParameters.length;
     for (int i = 0; i < node.typeParameters.length; ++i) {
       _typeParameters[node.typeParameters[i]] = objectTable.getOrAddObject(
diff --git a/pkg/vm/lib/bytecode/source_positions.dart b/pkg/vm/lib/bytecode/source_positions.dart
index ec56aa15..5d28c90 100644
--- a/pkg/vm/lib/bytecode/source_positions.dart
+++ b/pkg/vm/lib/bytecode/source_positions.dart
@@ -15,6 +15,9 @@
 
 /// Maintains mapping between bytecode instructions and source positions.
 class SourcePositions {
+  // Special value of fileOffset which marks synthetic code without source
+  // position.
+  static const syntheticCodeMarker = -1;
   // Special value of fileOffset which marks yield point.
   static const yieldPointMarker = -2;
 
@@ -26,7 +29,7 @@
 
   void add(int pc, int fileOffset) {
     assert(pc > _lastPc);
-    assert(fileOffset >= 0);
+    assert((fileOffset >= 0) || (fileOffset == syntheticCodeMarker));
     if (fileOffset != _lastOffset) {
       _positions.add(pc);
       _positions.add(fileOffset);
diff --git a/pkg/vm/lib/constants_error_reporter.dart b/pkg/vm/lib/constants_error_reporter.dart
deleted file mode 100644
index 724f5d8..0000000
--- a/pkg/vm/lib/constants_error_reporter.dart
+++ /dev/null
@@ -1,31 +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.
-
-/// Defines [ForwardConstantEvaluationErrors], an implementation of
-/// [constants.ErrorReporter] which uses package:front_end to report errors.
-library vm.constants_error_reporter;
-
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
-    as constants;
-
-import 'package:front_end/src/api_unstable/vm.dart'
-    show CompilerContext, LocatedMessage, Severity;
-
-import 'package:kernel/ast.dart' show InvalidExpression;
-
-class ForwardConstantEvaluationErrors implements constants.ErrorReporter {
-  // This will get the currently active [CompilerContext] from a zone variable.
-  // If there is no active context, this will throw.
-  final CompilerContext compilerContext = CompilerContext.current;
-
-  @override
-  void report(LocatedMessage message, List<LocatedMessage> context) {
-    compilerContext.options.report(message, Severity.error, context: context);
-  }
-
-  @override
-  void reportInvalidExpression(InvalidExpression node) {
-    // Assumed to be already reported.
-  }
-}
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index ced23df..49262b7 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -13,11 +13,6 @@
 import 'package:build_integration/file_system/multi_root.dart'
     show MultiRootFileSystem, MultiRootFileSystemEntity;
 
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
-    as constants;
-
 import 'package:front_end/src/api_unstable/vm.dart'
     show
         CompilerContext,
@@ -38,21 +33,18 @@
         printDiagnosticMessage;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-import 'package:kernel/ast.dart'
-    show Component, Field, Library, Reference, StaticGet;
+import 'package:kernel/ast.dart' show Component, Library, Reference;
 import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
 import 'package:kernel/binary/limited_ast_to_binary.dart'
     show LimitedBinaryPrinter;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/target/targets.dart' show Target, TargetFlags, getTarget;
-import 'package:kernel/vm/constants_native_effects.dart' as vm_constants;
 
 import 'bytecode/bytecode_serialization.dart' show BytecodeSizeStatistics;
 import 'bytecode/gen_bytecode.dart'
     show generateBytecode, createFreshComponentWithBytecode;
 import 'bytecode/options.dart' show BytecodeOptions;
 
-import 'constants_error_reporter.dart' show ForwardConstantEvaluationErrors;
 import 'target/install.dart' show installAdditionalTargets;
 import 'transformations/devirtualization.dart' as devirtualization
     show transformComponent;
@@ -106,9 +98,6 @@
       help: 'The values for the environment constants (e.g. -Dkey=value).');
   args.addFlag('enable-asserts',
       help: 'Whether asserts will be enabled.', defaultsTo: false);
-  args.addFlag('enable-constant-evaluation',
-      help: 'Whether kernel constant evaluation will be enabled.',
-      defaultsTo: true);
   args.addFlag('split-output-by-packages',
       help:
           'Split resulting kernel file into multiple files (one per package).',
@@ -167,7 +156,6 @@
   final bool genBytecode = options['gen-bytecode'];
   final bool dropAST = options['drop-ast'];
   final bool enableAsserts = options['enable-asserts'];
-  final bool enableConstantEvaluation = options['enable-constant-evaluation'];
   final bool useProtobufTreeShaker = options['protobuf-tree-shaker'];
   final bool splitOutputByPackages = options['split-output-by-packages'];
   final List<String> experimentalFlags = options['enable-experiment'];
@@ -231,7 +219,6 @@
       genBytecode: genBytecode,
       bytecodeOptions: bytecodeOptions,
       dropAST: dropAST && !splitOutputByPackages,
-      enableConstantEvaluation: enableConstantEvaluation,
       useProtobufTreeShaker: useProtobufTreeShaker);
 
   errorPrinter.printCompilationMessages();
@@ -284,7 +271,6 @@
     bool genBytecode: false,
     BytecodeOptions bytecodeOptions,
     bool dropAST: false,
-    bool enableConstantEvaluation: true,
     bool useProtobufTreeShaker: false}) async {
   // Replace error handler to detect if there are compilation errors.
   final errorDetector =
@@ -303,7 +289,6 @@
         component,
         useGlobalTypeFlowAnalysis,
         environmentDefines,
-        enableConstantEvaluation,
         useProtobufTreeShaker,
         errorDetector);
   }
@@ -354,13 +339,11 @@
     Component component,
     bool useGlobalTypeFlowAnalysis,
     Map<String, String> environmentDefines,
-    bool enableConstantEvaluation,
     bool useProtobufTreeShaker,
     ErrorDetector errorDetector) async {
   if (errorDetector.hasCompilationErrors) return;
 
   final coreTypes = new CoreTypes(component);
-  _patchVmConstants(coreTypes);
 
   // TODO(alexmarkov, dmitryas): Consider doing canonicalization of identical
   // mixin applications when creating mixin applications in frontend,
@@ -370,13 +353,6 @@
   // when building a platform dill file for VM/JIT case.
   mixin_deduplication.transformComponent(component);
 
-  if (enableConstantEvaluation) {
-    await _performConstantEvaluation(
-        source, compilerOptions, component, coreTypes, environmentDefines);
-
-    if (errorDetector.hasCompilationErrors) return;
-  }
-
   if (useGlobalTypeFlowAnalysis) {
     globalTypeFlow.transformComponent(
         compilerOptions.target, coreTypes, component);
@@ -427,40 +403,6 @@
   });
 }
 
-Future _performConstantEvaluation(
-    Uri source,
-    CompilerOptions compilerOptions,
-    Component component,
-    CoreTypes coreTypes,
-    Map<String, String> environmentDefines) async {
-  final vmConstants = new vm_constants.VmConstantsBackend(coreTypes);
-
-  await runWithFrontEndCompilerContext(source, compilerOptions, component, () {
-    // TFA will remove constants fields which are unused (and respects the
-    // vm/embedder entrypoints).
-    constants.transformComponent(component, vmConstants, environmentDefines,
-        new ForwardConstantEvaluationErrors(),
-        keepFields: true,
-        evaluateAnnotations: true,
-        desugarSets: !compilerOptions.target.supportsSetLiterals);
-  });
-}
-
-void _patchVmConstants(CoreTypes coreTypes) {
-  // Fix Endian.host to be a const field equal to Endial.little instead of
-  // a final field. VM does not support big-endian architectures at the
-  // moment.
-  // Can't use normal patching process for this because CFE does not
-  // support patching fields.
-  // See http://dartbug.com/32836 for the background.
-  final Field host =
-      coreTypes.index.getMember('dart:typed_data', 'Endian', 'host');
-  host.isConst = true;
-  host.initializer = new StaticGet(
-      coreTypes.index.getMember('dart:typed_data', 'Endian', 'little'))
-    ..parent = host;
-}
-
 class ErrorDetector {
   final DiagnosticMessageHandler previousErrorHandler;
   bool hasCompilationErrors = false;
diff --git a/pkg/vm/lib/target/dart_runner.dart b/pkg/vm/lib/target/dart_runner.dart
index 923898e..270f365 100644
--- a/pkg/vm/lib/target/dart_runner.dart
+++ b/pkg/vm/lib/target/dart_runner.dart
@@ -32,10 +32,10 @@
         // PRODUCT mode.
         'dart:mirrors',
 
-        'dart:profiler',
         'dart:typed_data',
         'dart:nativewrappers',
         'dart:io',
+        'dart:wasm',
 
         // Required for dart_runner.
         'dart:fuchsia.builtin',
@@ -43,4 +43,9 @@
         'dart:fuchsia',
         'dart:vmservice_io',
       ];
+
+  @override
+  List<String> get extraRequiredLibrariesPlatform => const <String>[
+        'dart:profiler',
+      ];
 }
diff --git a/pkg/vm/lib/target/flutter.dart b/pkg/vm/lib/target/flutter.dart
index ed4683c..8022a27 100644
--- a/pkg/vm/lib/target/flutter.dart
+++ b/pkg/vm/lib/target/flutter.dart
@@ -37,10 +37,10 @@
         // PRODUCT mode.
         'dart:mirrors',
 
-        'dart:profiler',
         'dart:typed_data',
         'dart:nativewrappers',
         'dart:io',
+        'dart:wasm',
 
         // Required for flutter.
         'dart:ui',
@@ -48,12 +48,20 @@
       ];
 
   @override
+  List<String> get extraRequiredLibrariesPlatform => const <String>[
+        'dart:profiler',
+      ];
+
+  @override
   void performPreConstantEvaluationTransformations(
       Component component,
       CoreTypes coreTypes,
       List<Library> libraries,
       DiagnosticReporter diagnosticReporter,
       {void logger(String msg)}) {
+    super.performPreConstantEvaluationTransformations(
+        component, coreTypes, libraries, diagnosticReporter,
+        logger: logger);
     if (flags.trackWidgetCreation) {
       if (_widgetTracker == null) {
         _widgetTracker = WidgetCreatorTracker();
diff --git a/pkg/vm/lib/target/flutter_runner.dart b/pkg/vm/lib/target/flutter_runner.dart
index 9266f3a..53363e2 100644
--- a/pkg/vm/lib/target/flutter_runner.dart
+++ b/pkg/vm/lib/target/flutter_runner.dart
@@ -32,10 +32,10 @@
         // PRODUCT mode.
         'dart:mirrors',
 
-        'dart:profiler',
         'dart:typed_data',
         'dart:nativewrappers',
         'dart:io',
+        'dart:wasm',
 
         // Required for flutter_runner.
         'dart:fuchsia.builtin',
@@ -44,4 +44,9 @@
         'dart:vmservice_io',
         'dart:ui',
       ];
+
+  @override
+  List<String> get extraRequiredLibrariesPlatform => const <String>[
+        'dart:profiler',
+      ];
 }
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 8a6dc24..23a6832 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -6,6 +6,7 @@
 import 'dart:core' hide MapEntry;
 
 import 'package:kernel/ast.dart';
+import 'package:kernel/clone.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/target/targets.dart';
@@ -68,7 +69,6 @@
         // PRODUCT mode.
         'dart:mirrors',
 
-        'dart:profiler',
         'dart:typed_data',
         'dart:vmservice_io',
         'dart:_vmservice',
@@ -76,6 +76,53 @@
         'dart:nativewrappers',
         'dart:io',
         'dart:cli',
+        'dart:wasm',
+      ];
+
+  @override
+  List<String> get extraRequiredLibrariesPlatform => const <String>[
+        'dart:profiler',
+      ];
+
+  void _patchVmConstants(CoreTypes coreTypes) {
+    // Fix Endian.host to be a const field equal to Endian.little instead of
+    // a final field. VM does not support big-endian architectures at the
+    // moment.
+    // Can't use normal patching process for this because CFE does not
+    // support patching fields.
+    // See http://dartbug.com/32836 for the background.
+    final Field host =
+        coreTypes.index.getMember('dart:typed_data', 'Endian', 'host');
+    final Field little =
+        coreTypes.index.getMember('dart:typed_data', 'Endian', 'little');
+    host.isConst = true;
+    host.initializer = new CloneVisitor().clone(little.initializer)
+      ..parent = host;
+  }
+
+  @override
+  void performPreConstantEvaluationTransformations(
+      Component component,
+      CoreTypes coreTypes,
+      List<Library> libraries,
+      DiagnosticReporter diagnosticReporter,
+      {void logger(String msg)}) {
+    super.performPreConstantEvaluationTransformations(
+        component, coreTypes, libraries, diagnosticReporter,
+        logger: logger);
+    _patchVmConstants(coreTypes);
+  }
+
+  @override
+  List<String> get extraIndexedLibraries => const <String>[
+        // TODO(askesc): When the VM supports set literals, we no longer
+        // need to index dart:collection, as it is only needed for desugaring of
+        // const sets. We can remove it from this list at that time.
+        "dart:collection",
+        // TODO(askesc): This is for the VM host endian optimization, which
+        // could possibly be done more cleanly after the VM no longer supports
+        // doing constant evaluation on its own. See http://dartbug.com/32836
+        "dart:typed_data",
       ];
 
   @override
@@ -307,6 +354,13 @@
         ]));
   }
 
+  // In addition to the default implementation, we allow VM tests to import
+  // private platform libraries - such as `dart:_internal` - for testing
+  // purposes.
+  bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
+      super.allowPlatformPrivateLibraryAccess(importer, imported) ||
+      importer.path.contains('runtime/tests/vm/dart');
+
   // TODO(sigmund,ahe): limit this to `dart-ext` libraries only (see
   // https://github.com/dart-lang/sdk/issues/29763).
   @override
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 667a2e9..6b47324 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -186,6 +186,8 @@
   final Constructor structFromPointer;
   final Procedure libraryLookupMethod;
   final Procedure abiMethod;
+  final Procedure pointerFromFunctionProcedure;
+  final Procedure nativeCallbackFunctionProcedure;
 
   /// Classes corresponding to [NativeType], indexed by [NativeType].
   final List<Class> nativeTypesClasses;
@@ -220,6 +222,10 @@
         libraryLookupMethod =
             index.getMember('dart:ffi', 'DynamicLibrary', 'lookup'),
         abiMethod = index.getTopLevelMember('dart:ffi', '_abi'),
+        pointerFromFunctionProcedure =
+            index.getTopLevelMember('dart:ffi', '_pointerFromFunction'),
+        nativeCallbackFunctionProcedure =
+            index.getTopLevelMember('dart:ffi', '_nativeCallbackFunction'),
         nativeTypesClasses = nativeTypeClassNames
             .map((name) => index.getClass('dart:ffi', name))
             .toList();
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 8bef2ca..c82b64f 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -85,6 +85,12 @@
       : super(index, coreTypes, hierarchy, diagnosticReporter) {}
 
   @override
+  visitExtension(Extension node) {
+    // The extension and it's members are only metadata.
+    return node;
+  }
+
+  @override
   visitClass(Class node) {
     if (!hierarchy.isSubclassOf(node, structClass) || node == structClass) {
       return node;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 58b0acd..d7cc4b5 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -6,12 +6,16 @@
 
 import 'package:front_end/src/api_unstable/vm.dart'
     show
+        messageFfiExceptionalReturnNull,
+        messageFfiExpectedConstant,
+        templateFfiDartTypeMismatch,
+        templateFfiExpectedExceptionalReturn,
+        templateFfiExpectedNoExceptionalReturn,
+        templateFfiExtendsOrImplementsSealedClass,
+        templateFfiNotStatic,
         templateFfiTypeInvalid,
         templateFfiTypeMismatch,
-        templateFfiDartTypeMismatch,
-        templateFfiTypeUnsized,
-        templateFfiNotStatic,
-        templateFfiExtendsOrImplementsSealedClass;
+        templateFfiTypeUnsized;
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -55,7 +59,12 @@
   final Map<Field, Procedure> replacedGetters;
   final Map<Field, Procedure> replacedSetters;
 
-  bool isFfiLibrary;
+  Library currentLibrary;
+  bool get isFfiLibrary => currentLibrary == ffiLibrary;
+
+  // Used to create private top-level fields with unique names for each
+  // callback.
+  int callbackCount = 0;
 
   _FfiUseSiteTransformer(
       LibraryIndex index,
@@ -68,7 +77,8 @@
 
   @override
   TreeNode visitLibrary(Library node) {
-    isFfiLibrary = node == ffiLibrary;
+    currentLibrary = node;
+    callbackCount = 0;
     return super.visitLibrary(node);
   }
 
@@ -78,6 +88,11 @@
     try {
       _ensureNotExtendsOrImplementsSealedClass(node);
       return super.visitClass(node);
+    } on _FfiStaticTypeError {
+      // It's OK to swallow the exception because the diagnostics issued will
+      // cause compilation to fail. By continuing, we can report more
+      // diagnostics before compilation ends.
+      return super.visitClass(node);
     } finally {
       env.thisType = null;
     }
@@ -115,31 +130,89 @@
     Member target = node.target;
     try {
       if (target == fromFunctionMethod) {
-        DartType nativeType =
+        final DartType nativeType =
             InterfaceType(nativeFunctionClass, [node.arguments.types[0]]);
-        Expression func = node.arguments.positional[0];
-        DartType dartType = func.getStaticType(env);
+        final Expression func = node.arguments.positional[0];
+        final DartType dartType = func.getStaticType(env);
 
-        _ensureIsStatic(func);
+        _ensureIsStaticFunction(func);
+
         // TODO(36730): Allow passing/returning structs by value.
         _ensureNativeTypeValid(nativeType, node);
         _ensureNativeTypeToDartType(nativeType, dartType, node);
 
         // Check `exceptionalReturn`'s type.
         final FunctionType funcType = dartType;
-        final Expression exceptionalReturn = node.arguments.positional[1];
-        final DartType returnType = exceptionalReturn.getStaticType(env);
+        final NativeType expectedReturn = getType(
+            ((node.arguments.types[0] as FunctionType).returnType
+                    as InterfaceType)
+                .classNode);
 
-        if (!env.isSubtypeOf(returnType, funcType.returnType)) {
-          diagnosticReporter.report(
-              templateFfiDartTypeMismatch.withArguments(
-                  returnType, funcType.returnType),
-              exceptionalReturn.fileOffset,
-              1,
-              exceptionalReturn.location.file);
+        if (expectedReturn == NativeType.kVoid ||
+            expectedReturn == NativeType.kPointer) {
+          if (node.arguments.positional.length > 1) {
+            diagnosticReporter.report(
+                templateFfiExpectedNoExceptionalReturn
+                    .withArguments(funcType.returnType),
+                node.fileOffset,
+                1,
+                node.location.file);
+            return node;
+          }
+          node.arguments.positional.add(NullLiteral()..parent = node);
+        } else {
+          // The exceptional return value is not optional for other return
+          // types.
+          if (node.arguments.positional.length < 2) {
+            diagnosticReporter.report(
+                templateFfiExpectedExceptionalReturn
+                    .withArguments(funcType.returnType),
+                node.fileOffset,
+                1,
+                node.location.file);
+            return node;
+          }
+
+          final Expression exceptionalReturn = node.arguments.positional[1];
+
+          // The exceptional return value must be a constant so that it be
+          // referenced by precompiled trampoline's object pool.
+          if (exceptionalReturn is! BasicLiteral &&
+              !(exceptionalReturn is ConstantExpression &&
+                  exceptionalReturn.constant is PrimitiveConstant)) {
+            diagnosticReporter.report(messageFfiExpectedConstant,
+                node.fileOffset, 1, node.location.file);
+            return node;
+          }
+
+          // Moreover it may not be null.
+          if (exceptionalReturn is NullLiteral ||
+              (exceptionalReturn is ConstantExpression &&
+                  exceptionalReturn.constant is NullConstant)) {
+            diagnosticReporter.report(messageFfiExceptionalReturnNull,
+                node.fileOffset, 1, node.location.file);
+            return node;
+          }
+
+          final DartType returnType = exceptionalReturn.getStaticType(env);
+
+          if (!env.isSubtypeOf(returnType, funcType.returnType)) {
+            diagnosticReporter.report(
+                templateFfiDartTypeMismatch.withArguments(
+                    returnType, funcType.returnType),
+                exceptionalReturn.fileOffset,
+                1,
+                exceptionalReturn.location.file);
+            return node;
+          }
         }
+        return _replaceFromFunction(node);
       }
-    } catch (_FfiStaticTypeError) {}
+    } on _FfiStaticTypeError {
+      // It's OK to swallow the exception because the diagnostics issued will
+      // cause compilation to fail. By continuing, we can report more
+      // diagnostics before compilation ends.
+    }
 
     return node;
   }
@@ -151,10 +224,10 @@
   // 'lookupFunction' are constants, so by inlining the call to 'asFunction' at
   // the call-site, we ensure that there are no generic calls to 'asFunction'.
   //
-  // We will not detect dynamic invocations of 'asFunction' -- these are handled
-  // by the stub in 'dynamic_library_patch.dart'. Dynamic invocations of
-  // 'lookupFunction' (and 'asFunction') are not legal and throw a runtime
-  // exception.
+  // We will not detect dynamic invocations of 'asFunction' and
+  // 'lookupFunction': these are handled by the stubs in 'ffi_patch.dart' and
+  // 'dynamic_library_patch.dart'. Dynamic invocations of 'lookupFunction' (and
+  // 'asFunction') are not legal and throw a runtime exception.
   Expression _replaceLookupFunction(MethodInvocation node) {
     // The generated code looks like:
     //
@@ -176,6 +249,39 @@
         Arguments([lookupResult], types: [dartSignature, nativeSignature]));
   }
 
+  // We need to rewrite calls to 'fromFunction' into two calls, representing the
+  // compile-time and run-time aspects of creating the closure:
+  //
+  // final dynamic _#ffiCallback0 = Pointer.fromFunction<T>(f, e) =>
+  //   _pointerFromFunction<NativeFunction<T>>(
+  //     _nativeCallbackFunction<T>(f, e));
+  //
+  //  ... _#ffiCallback0 ...
+  //
+  // We must implement this as a Kernel rewrite because <T> must be a
+  // compile-time constant to any invocation of '_nativeCallbackFunction'.
+  //
+  // Creating this closure requires a runtime call, so we save the result in a
+  // synthetic top-level field to avoid recomputing it.
+  Expression _replaceFromFunction(StaticInvocation node) {
+    final nativeFunctionType =
+        InterfaceType(nativeFunctionClass, node.arguments.types);
+    final Field field = Field(
+        Name("_#ffiCallback${callbackCount++}", currentLibrary),
+        type: InterfaceType(pointerClass, [nativeFunctionType]),
+        initializer: StaticInvocation(
+            pointerFromFunctionProcedure,
+            Arguments([
+              StaticInvocation(nativeCallbackFunctionProcedure, node.arguments)
+            ], types: [
+              nativeFunctionType
+            ])),
+        isStatic: true,
+        isFinal: true);
+    currentLibrary.addMember(field);
+    return StaticGet(field);
+  }
+
   @override
   visitMethodInvocation(MethodInvocation node) {
     super.visitMethodInvocation(node);
@@ -233,7 +339,11 @@
         _ensureNativeTypeSized(nativeType, node, target.name);
         _ensureNativeTypeToDartType(nativeType, dartType, node);
       }
-    } catch (_FfiStaticTypeError) {}
+    } on _FfiStaticTypeError {
+      // It's OK to swallow the exception because the diagnostics issued will
+      // cause compilation to fail. By continuing, we can report more
+      // diagnostics before compilation ends.
+    }
 
     return node;
   }
@@ -322,22 +432,17 @@
     return false;
   }
 
-  void _ensureIsStatic(Expression node) {
-    if (!_isStatic(node)) {
-      diagnosticReporter.report(
-          templateFfiNotStatic.withArguments(fromFunctionMethod.name.name),
-          node.fileOffset,
-          1,
-          node.location.file);
-      throw _FfiStaticTypeError();
+  void _ensureIsStaticFunction(Expression node) {
+    if ((node is StaticGet && node.target is Procedure) ||
+        (node is ConstantExpression && node.constant is TearOffConstant)) {
+      return;
     }
-  }
-
-  bool _isStatic(Expression node) {
-    if (node is StaticGet) {
-      return node.target is Procedure;
-    }
-    return node is ConstantExpression;
+    diagnosticReporter.report(
+        templateFfiNotStatic.withArguments(fromFunctionMethod.name.name),
+        node.fileOffset,
+        1,
+        node.location.file);
+    throw _FfiStaticTypeError();
   }
 
   Class _extendsOrImplementsSealedClass(Class klass) {
@@ -368,6 +473,7 @@
           klass.fileOffset,
           1,
           klass.location.file);
+      throw _FfiStaticTypeError();
     }
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 9b322a9..2d434d2 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -111,9 +111,10 @@
   // are cached in _InvocationsCache using selector and args as a key.
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       (other is _Invocation) &&
-      (this.selector == other.selector) &&
-      (this.args == other.args);
+          (this.selector == other.selector) &&
+          (this.args == other.args);
 
   @override
   int get hashCode => (selector.hashCode ^ args.hashCode + 31) & kHashMask;
@@ -920,7 +921,9 @@
   int get hashCode => _id;
 
   @override
-  bool operator ==(other) => (other is _ClassData) && (this._id == other._id);
+  bool operator ==(other) =>
+      identical(this, other) ||
+      (other is _ClassData) && (this._id == other._id);
 
   @override
   int compareTo(_ClassData other) => this._id.compareTo(other._id);
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index de3cabe..d0c284e 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -38,7 +38,8 @@
   int get hashCode => callKind.hashCode;
 
   @override
-  bool operator ==(other) => other is Selector && other.callKind == callKind;
+  bool operator ==(other) =>
+      identical(this, other) || other is Selector && other.callKind == callKind;
 
   /// Static approximation of Dart return type.
   DartType get staticReturnType {
@@ -107,6 +108,7 @@
 
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       other is DirectSelector && super == (other) && other.member == member;
 
   @override
@@ -125,6 +127,7 @@
 
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       other is InterfaceSelector && super == (other) && other.member == member;
 
   @override
@@ -140,7 +143,8 @@
   int get hashCode => (super.hashCode + 37) & kHashMask;
 
   @override
-  bool operator ==(other) => other is VirtualSelector && super == (other);
+  bool operator ==(other) =>
+      identical(this, other) || other is VirtualSelector && super == (other);
 
   @override
   String toString() => 'virtual ${_callKindPrefix}[$member]';
@@ -163,6 +167,7 @@
 
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       other is DynamicSelector && super == (other) && other.name == name;
 
   @override
@@ -207,6 +212,7 @@
 
   @override
   bool operator ==(other) {
+    if (identical(this, other)) return true;
     if (other is Args<T> &&
         (this.values.length == other.values.length) &&
         (this.names.length == other.names.length)) {
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index 26f3c47..3f06a5d 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -55,15 +55,16 @@
 
   @override
   visitClass(Class klass) {
-    if (!klass.isAbstract) {
-      var type = _annotationsDefineRoot(klass.annotations);
-      if (type != null) {
-        if (type != PragmaEntryPointType.Default) {
-          throw "Error: pragma entry-point definition on a class must evaluate "
-              "to null, true or false. See entry_points_pragma.md.";
-        }
+    final type = _annotationsDefineRoot(klass.annotations);
+    if (type != null) {
+      if (type != PragmaEntryPointType.Default) {
+        throw "Error: pragma entry-point definition on a class must evaluate "
+            "to null, true or false. See entry_points_pragma.md.";
+      }
+      if (!klass.isAbstract) {
         entryPoints.addAllocatedClass(klass);
       }
+      nativeCodeOracle.addClassReferencedFromNativeCode(klass);
     }
     currentClass = klass;
     klass.visitChildren(this);
@@ -167,12 +168,20 @@
 class NativeCodeOracle {
   final LibraryIndex _libraryIndex;
   final Set<Member> _membersReferencedFromNativeCode = new Set<Member>();
+  final Set<Class> _classesReferencedFromNativeCode = new Set<Class>();
   final PragmaAnnotationParser _matcher;
 
   NativeCodeOracle(this._libraryIndex, this._matcher) {
     assertx(_matcher != null);
   }
 
+  void addClassReferencedFromNativeCode(Class klass) {
+    _classesReferencedFromNativeCode.add(klass);
+  }
+
+  bool isClassReferencedFromNativeCode(Class klass) =>
+      _classesReferencedFromNativeCode.contains(klass);
+
   void setMemberReferencedFromNativeCode(Member member) {
     _membersReferencedFromNativeCode.add(member);
   }
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index d6f8fb3..7254e6c 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -945,9 +945,16 @@
 
   @override
   TypeExpr visitMethodInvocation(MethodInvocation node) {
-    final receiver = _visit(node.receiver);
+    final receiverNode = node.receiver;
+    final receiver = _visit(receiverNode);
     final args = _visitArguments(receiver, node.arguments);
     final target = node.interfaceTarget;
+    if (receiverNode is ConstantExpression && node.name.name == '[]') {
+      Constant constant = receiverNode.constant;
+      if (constant is ListConstant) {
+        return _handleIndexingIntoListConstant(constant);
+      }
+    }
     if (target == null) {
       if (node.name.name == '==') {
         assertx(args.values.length == 2);
@@ -993,6 +1000,24 @@
     }
   }
 
+  TypeExpr _handleIndexingIntoListConstant(ListConstant list) {
+    final elementTypes = new Set<Type>();
+    for (var element in list.entries) {
+      elementTypes.add(constantAllocationCollector.typeFor(element));
+    }
+    switch (elementTypes.length) {
+      case 0:
+        return new Type.empty();
+      case 1:
+        return elementTypes.single;
+      default:
+        final join = new Join(null, list.typeArgument);
+        join.values.addAll(elementTypes);
+        _summary.add(join);
+        return join;
+    }
+  }
+
   @override
   TypeExpr visitPropertyGet(PropertyGet node) {
     var receiver = _visit(node.receiver);
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 5843438..a33eb29 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -349,6 +349,7 @@
   final Set<Class> _usedClasses = new Set<Class>();
   final Set<Class> _classesUsedInType = new Set<Class>();
   final Set<Member> _usedMembers = new Set<Member>();
+  final Set<Extension> _usedExtensions = new Set<Extension>();
   final Set<Typedef> _usedTypedefs = new Set<Typedef>();
   _TreeShakerTypeVisitor typeVisitor;
   _TreeShakerConstantVisitor constantVisitor;
@@ -367,10 +368,13 @@
     _pass2.transform(component);
   }
 
+  bool isClassReferencedFromNativeCode(Class c) =>
+      typeFlowAnalysis.nativeCodeOracle.isClassReferencedFromNativeCode(c);
   bool isClassUsed(Class c) => _usedClasses.contains(c);
   bool isClassUsedInType(Class c) => _classesUsedInType.contains(c);
   bool isClassAllocated(Class c) => typeFlowAnalysis.isClassAllocated(c);
   bool isMemberUsed(Member m) => _usedMembers.contains(m);
+  bool isExtensionUsed(Extension e) => _usedExtensions.contains(e);
   bool isMemberBodyReachable(Member m) => typeFlowAnalysis.isMemberUsed(m);
   bool isFieldInitializerReachable(Field f) =>
       typeFlowAnalysis.isFieldInitializerUsed(f);
@@ -432,6 +436,27 @@
       }
 
       transformList(m.annotations, _pass1, m);
+
+      // If the member is kept alive we need to keep the extension alive.
+      if (m.isExtensionMember) {
+        // The AST should have exactly one [Extension] for [m].
+        final extension = m.enclosingLibrary.extensions.firstWhere((extension) {
+          return extension.members
+              .any((descriptor) => descriptor.member.asMember == m);
+        }, orElse: () => null);
+        assertx(extension != null);
+
+        // Ensure we retain the [Extension] itself (though members might be
+        // shaken)
+        addUsedExtension(extension);
+      }
+    }
+  }
+
+  void addUsedExtension(Extension node) {
+    if (_usedExtensions.add(node)) {
+      transformList(node.typeParameters, _pass1, node);
+      node.onType?.accept(typeVisitor);
     }
   }
 
@@ -580,8 +605,16 @@
   }
 
   @override
+  Extension visitExtension(Extension node) {
+    // The extension can be considered a weak node, we'll only retain it if
+    // normal code references any of it's members.
+    return node;
+  }
+
+  @override
   TreeNode visitClass(Class node) {
-    if (shaker.isClassAllocated(node)) {
+    if (shaker.isClassAllocated(node) ||
+        shaker.isClassReferencedFromNativeCode(node)) {
       shaker.addClassUsedInType(node);
     }
     transformList(node.constructors, this, node);
@@ -987,6 +1020,31 @@
     return node;
   }
 
+  @override
+  Extension visitExtension(Extension node) {
+    if (shaker.isExtensionUsed(node)) {
+      int writeIndex = 0;
+      for (int i = 0; i < node.members.length; ++i) {
+        final ExtensionMemberDescriptor descriptor = node.members[i];
+
+        // To avoid depending on the order in which members and extensions are
+        // visited during the transformation, we handle both cases: either the
+        // member was already removed or it will be removed later.
+        final Reference memberReference = descriptor.member;
+        final bool isBound = memberReference.node != null;
+        if (isBound && shaker.isMemberUsed(memberReference.node)) {
+          node.members[writeIndex++] = descriptor;
+        }
+      }
+      node.members.length = writeIndex;
+
+      // We only retain the extension if at least one member is retained.
+      assertx(node.members.length > 0);
+      return node;
+    }
+    return null;
+  }
+
   void _makeUnreachableBody(FunctionNode function) {
     if (function.body != null) {
       function.body = new ExpressionStatement(new Throw(new StringLiteral(
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 9c52e34..9d34b39 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -215,6 +215,7 @@
 
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       (other is NullableType) && (this.baseType == other.baseType);
 
   @override
@@ -329,6 +330,7 @@
 
   @override
   bool operator ==(other) {
+    if (identical(this, other)) return true;
     if ((other is SetType) && (types.length == other.types.length)) {
       for (int i = 0; i < types.length; i++) {
         if (types[i] != other.types[i]) {
@@ -502,6 +504,7 @@
 
   @override
   bool operator ==(other) =>
+      identical(this, other) ||
       (other is ConeType) && (this.dartType == other.dartType);
 
   @override
@@ -704,6 +707,7 @@
 
   @override
   bool operator ==(other) {
+    if (identical(this, other)) return true;
     if (other is ConcreteType) {
       if (this.classId != other.classId ||
           this.numImmediateTypeArgs != other.numImmediateTypeArgs) {
@@ -870,6 +874,7 @@
 
   @override
   operator ==(other) {
+    if (identical(this, other)) return true;
     if (other is RuntimeType) {
       if (other._type != _type) return false;
       assertx(numImmediateTypeArgs == other.numImmediateTypeArgs);
diff --git a/pkg/vm/test/frontend_server_flutter.dart b/pkg/vm/test/frontend_server_flutter.dart
index be1ee67..ee88962 100644
--- a/pkg/vm/test/frontend_server_flutter.dart
+++ b/pkg/vm/test/frontend_server_flutter.dart
@@ -52,6 +52,7 @@
           f.uri.toString().contains("/packages/")) &&
       f.uri.toString().endsWith("/.packages")));
 
+  List<String> allCompilationErrors = [];
   for (File dotPackage in dotPackagesFiles) {
     Directory tempDir;
     Directory systemTempDir = Directory.systemTemp;
@@ -60,17 +61,35 @@
       Directory testDir =
           new Directory.fromUri(dotPackage.parent.uri.resolve("test/"));
       if (!testDir.existsSync()) continue;
+      if (testDir.toString().contains("packages/flutter_web_plugins/test/")) {
+        // TODO(jensj): Figure out which tests are web-tests, and compile those
+        // in a setup that can handle that.
+        continue;
+      }
       print("Go for $testDir");
-      await attemptStuff(
+      List<String> compilationErrors = await attemptStuff(
           tempDir, flutterPlatformDirectory, dotPackage, testDir);
+      if (compilationErrors.isNotEmpty) {
+        print("Notice that we had ${compilationErrors.length} "
+            "compilation errors for $testDir");
+        allCompilationErrors.addAll(compilationErrors);
+      }
     } finally {
       tempDir.delete(recursive: true);
     }
   }
+  if (allCompilationErrors.isNotEmpty) {
+    print("Had a total of ${allCompilationErrors.length} compilation errors:");
+    allCompilationErrors.forEach(print);
+    throw "Had a total of ${allCompilationErrors.length} compilation errors";
+  }
 }
 
-void attemptStuff(Directory tempDir, Directory flutterPlatformDirectory,
-    File dotPackage, Directory testDir) async {
+Future<List<String>> attemptStuff(
+    Directory tempDir,
+    Directory flutterPlatformDirectory,
+    File dotPackage,
+    Directory testDir) async {
   File dillFile = new File('${tempDir.path}/dill.dill');
   if (dillFile.existsSync()) {
     throw "$dillFile already exists.";
@@ -90,10 +109,20 @@
     // '--unsafe-package-serialization',
   ];
 
+  bool shouldSkip(File f) {
+    // TODO(jensj): Come up with a better way to (temporarily) skip some tests.
+    List<String> pathSegments = f.uri.pathSegments;
+    if (pathSegments.sublist(pathSegments.length - 5).join("/") ==
+        "packages/flutter/test/widgets/html_element_view_test.dart") {
+      return true;
+    }
+    return false;
+  }
+
   List<File> testFiles = new List<File>.from(testDir
       .listSync(recursive: true)
-      .where((f) => f.path.endsWith("_test.dart")));
-  if (testFiles.isEmpty) return;
+      .where((f) => f.path.endsWith("_test.dart") && !shouldSkip(f)));
+  if (testFiles.isEmpty) return [];
 
   Stopwatch stopwatch = new Stopwatch()..start();
 
@@ -122,21 +151,32 @@
   inputStreamController
       .add('compile ${testFileIterator.current.path}\n'.codeUnits);
   int compilations = 0;
+  List<String> compilationErrors = [];
   receivedResults.stream.listen((Result compiledResult) {
     stdout.write(" --- done in ${stopwatch2.elapsedMilliseconds} ms\n");
     stopwatch2.reset();
-    compiledResult.expectNoErrors();
-
-    List<int> resultBytes = dillFile.readAsBytesSync();
-    Component component = loadComponentFromBytes(platformData);
-    component = loadComponentFromBytes(resultBytes, component);
-    verifyComponent(component);
-    print("        => verified in ${stopwatch2.elapsedMilliseconds} ms.");
+    bool error = false;
+    try {
+      compiledResult.expectNoErrors();
+    } catch (e) {
+      print("Got errors. Compiler output for this compile:");
+      outputParser.allReceived.forEach(print);
+      compilationErrors.add(testFileIterator.current.path);
+      error = true;
+    }
+    if (!error) {
+      List<int> resultBytes = dillFile.readAsBytesSync();
+      Component component = loadComponentFromBytes(platformData);
+      component = loadComponentFromBytes(resultBytes, component);
+      verifyComponent(component);
+      print("        => verified in ${stopwatch2.elapsedMilliseconds} ms.");
+    }
     stopwatch2.reset();
 
     inputStreamController.add('accept\n'.codeUnits);
     inputStreamController.add('reset\n'.codeUnits);
     compilations++;
+    outputParser.allReceived.clear();
 
     if (!testFileIterator.moveNext()) {
       inputStreamController.add('quit\n'.codeUnits);
@@ -160,6 +200,8 @@
 
   print("Did $compilations compilations and verifications in "
       "${stopwatch.elapsedMilliseconds} ms.");
+
+  return compilationErrors;
 }
 
 // The below is copied from incremental_compiler_test.dart,
@@ -176,7 +218,10 @@
   String _boundaryKey;
   bool _readingSources;
 
+  List<String> allReceived = new List<String>();
+
   void listener(String s) {
+    allReceived.add(s);
     if (_boundaryKey == null) {
       const String RESULT_OUTPUT_SPACE = 'result ';
       if (s.startsWith(RESULT_OUTPUT_SPACE)) {
diff --git a/pkg/vm/test/transformations/type_flow/annotation_matcher.dart b/pkg/vm/test/transformations/type_flow/annotation_matcher.dart
deleted file mode 100644
index 2b7f278..0000000
--- a/pkg/vm/test/transformations/type_flow/annotation_matcher.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:kernel/ast.dart';
-import 'package:kernel/core_types.dart';
-import 'package:vm/transformations/type_flow/utils.dart';
-import 'package:vm/transformations/pragma.dart';
-
-// Since we don't run the constants transformation in this test, we can't
-// recognize all pragma annotations precisely. Instead, we pattern match on
-// annotations which look like a pragma and assume that their options field
-// evaluates to true.
-class ExpressionPragmaAnnotationParser extends PragmaAnnotationParser {
-  final CoreTypes coreTypes;
-
-  ExpressionPragmaAnnotationParser(this.coreTypes);
-
-  ParsedPragma parsePragma(Expression annotation) {
-    assertx(annotation is! ConstantExpression);
-
-    String pragmaName;
-    Expression options;
-
-    if (annotation is ConstructorInvocation) {
-      if (annotation.constructedType.classNode != coreTypes.pragmaClass) {
-        return null;
-      }
-
-      if (annotation.arguments.types.length != 0 ||
-          (annotation.arguments.positional.length != 1 &&
-              annotation.arguments.positional.length != 2) ||
-          annotation.arguments.named.length != 0) {
-        throw "Cannot evaluate pragma annotation $annotation";
-      }
-
-      var arguments = annotation.arguments.positional;
-      var nameArg = arguments[0];
-      if (nameArg is StringLiteral) {
-        pragmaName = nameArg.value;
-      } else {
-        return null;
-      }
-
-      options = arguments.length > 1 ? arguments[1] : new NullLiteral();
-    }
-
-    switch (pragmaName) {
-      case kEntryPointPragmaName:
-        // We ignore the option because we can't properly evaluate it, assume
-        // it's true.
-        return new ParsedEntryPointPragma(PragmaEntryPointType.Default);
-      case kExactResultTypePragmaName:
-        if (options is TypeLiteral) {
-          return new ParsedResultTypeByTypePragma(options.type);
-        } else if (options is StringLiteral) {
-          return new ParsedResultTypeByPathPragma(options.value);
-        }
-        throw "Could not recognize option to $kExactResultTypePragmaName";
-      default:
-        return null;
-    }
-  }
-}
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index a58eb82..4ab863b 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -4,8 +4,6 @@
 
 import 'dart:io';
 
-import 'package:front_end/src/api_unstable/vm.dart'
-    show defaultExperimentalFlags, ExperimentalFlag;
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
@@ -16,7 +14,6 @@
 import 'package:vm/transformations/type_flow/native_code.dart';
 import 'package:vm/transformations/type_flow/summary_collector.dart';
 import 'package:vm/transformations/type_flow/analysis.dart';
-import 'annotation_matcher.dart' show ExpressionPragmaAnnotationParser;
 import 'package:kernel/target/targets.dart';
 
 import '../../common_test_utils.dart';
@@ -35,10 +32,7 @@
             hierarchy,
             new EmptyEntryPointsListener(),
             new NativeCodeOracle(
-                null,
-                defaultExperimentalFlags[ExperimentalFlag.constantUpdate2018]
-                    ? new ConstantPragmaAnnotationParser(coreTypes)
-                    : new ExpressionPragmaAnnotationParser(coreTypes)),
+                null, new ConstantPragmaAnnotationParser(coreTypes)),
             new GenericInterfacesInfoImpl(hierarchy));
 
   String print(TreeNode node) {
diff --git a/pkg/vm/test/transformations/type_flow/transformer_test.dart b/pkg/vm/test/transformations/type_flow/transformer_test.dart
index ae4764a..b51cbd3 100644
--- a/pkg/vm/test/transformations/type_flow/transformer_test.dart
+++ b/pkg/vm/test/transformations/type_flow/transformer_test.dart
@@ -4,8 +4,6 @@
 
 import 'dart:io';
 
-import 'package:front_end/src/api_unstable/vm.dart'
-    show defaultExperimentalFlags, ExperimentalFlag;
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
@@ -15,7 +13,6 @@
     show ConstantPragmaAnnotationParser;
 import 'package:vm/transformations/type_flow/transformer.dart'
     show transformComponent;
-import 'annotation_matcher.dart';
 
 import '../../common_test_utils.dart';
 
@@ -28,13 +25,8 @@
 
   final coreTypes = new CoreTypes(component);
 
-  component = transformComponent(
-      target,
-      coreTypes,
-      component,
-      defaultExperimentalFlags[ExperimentalFlag.constantUpdate2018]
-          ? new ConstantPragmaAnnotationParser(coreTypes)
-          : new ExpressionPragmaAnnotationParser(coreTypes));
+  component = transformComponent(target, coreTypes, component,
+      new ConstantPragmaAnnotationParser(coreTypes));
 
   final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
 
diff --git a/pkg/vm/test/unlinked_ast_to_text_test.dart b/pkg/vm/test/unlinked_ast_to_text_test.dart
new file mode 100644
index 0000000..ee580e2
--- /dev/null
+++ b/pkg/vm/test/unlinked_ast_to_text_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:expect/expect.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/binary/limited_ast_to_binary.dart';
+import 'package:vm/kernel_front_end.dart';
+
+main() async {
+  final outDir =
+      Directory.systemTemp.createTempSync("incremental_load_from_dill_test");
+
+  final dillFile = outDir.uri.resolve("dart2js.dart.dill").toFilePath();
+  final unlinkedDillFile =
+      outDir.uri.resolve("dart2js.dart.unlinked.dill").toFilePath();
+  final unlinkedDillTxtFile =
+      outDir.uri.resolve("dart2js.dart.unlinked dill.txt").toFilePath();
+
+  final executable = Platform.executable;
+  if (!executable.endsWith('out/ReleaseX64/dart')) {
+    return;
+  }
+
+  final platformDill = Uri.parse(executable).resolve('vm_platform.dill');
+
+  try {
+    final arguments = <String>[
+      '--no-link-platform',
+      '--platform=$platformDill',
+      '--output=$dillFile',
+      'pkg/compiler/lib/src/dart2js.dart',
+    ];
+
+    // Compile dart2js.dart.
+    final ArgParser argParser = createCompilerArgParser();
+    final int exitCode =
+        await runCompiler(argParser.parse(arguments), '<usage>');
+    Expect.equals(0, exitCode);
+
+    // Load the dart2js.dart.dill and write the unlinked version.
+    final component = loadComponentFromBinary(dillFile);
+    final IOSink sink = new File(unlinkedDillFile).openWrite();
+    final printer = new LimitedBinaryPrinter(
+        sink, (lib) => lib.importUri.scheme != 'dart', false);
+    printer.writeComponentFile(component);
+    await sink.close();
+
+    // Ensure we can load the unlinked dill file and ensure it doesn't include
+    // core libraries.
+    final unlinkedComponent = loadComponentFromBinary(unlinkedDillFile);
+    final coreLibraryCount = unlinkedComponent.libraries
+        .where(
+            (lib) => lib.importUri.scheme == 'dart' && lib.members.isNotEmpty)
+        .length;
+    Expect.equals(0, coreLibraryCount);
+
+    // Ensure we can print the unlinked kernel to text.
+    writeComponentToText(unlinkedComponent, path: unlinkedDillTxtFile);
+  } finally {
+    outDir.deleteSync(recursive: true);
+  }
+}
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 28dae68..74730b1 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -69,8 +69,8 @@
   [32] = Reserved
   [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [34] = Reserved
-  [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [36] = ICData dynamic target-name 'start', arg-desc CP#35
+  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [36] = Reserved
   [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [38] = Reserved
   [39] = EndClosureFunctionScope
@@ -78,10 +78,10 @@
 Closure #lib::asyncInFieldInitializer (field)::'<anonymous closure>' async (dart:async::Future < dart:core::int > x) -> dart:async::Future < dart:core::Null >
 ClosureCode {
   EntryFixed           2, 4
-  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   AllocateContext      0, 9
   PopLocal             r0
   Push                 r0
@@ -162,7 +162,7 @@
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 8
-  DynamicCall          CP#36, 2
+  DynamicCall          CP#35, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
@@ -177,10 +177,10 @@
   LoadConstant         r2, CP#11
   LoadConstant         r3, CP#11
   Frame                6
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#1
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 5
   StoreLocal           r5
@@ -321,7 +321,7 @@
   Push                 r0
   LoadContextVar       0, 0
   Push                 r6
-  DynamicCall          CP#30, 2
+  DynamicCall          CP#29, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 0
@@ -358,8 +358,8 @@
   [26] = Reserved
   [27] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [28] = Reserved
-  [29] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [30] = ICData dynamic target-name 'start', arg-desc CP#29
+  [29] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [30] = Reserved
   [31] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [32] = Reserved
 }
@@ -370,10 +370,10 @@
   LoadConstant         r2, CP#5
   LoadConstant         r3, CP#5
   Frame                6
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#6
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 2
   StoreLocal           r5
@@ -505,7 +505,7 @@
   LoadContextVar       0, 2
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#34, 2
+  DynamicCall          CP#33, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 2
@@ -546,8 +546,8 @@
   [30] = Reserved
   [31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [32] = Reserved
-  [33] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [34] = ICData dynamic target-name 'start', arg-desc CP#33
+  [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [34] = Reserved
   [35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
 }
@@ -558,10 +558,10 @@
   LoadConstant         r2, CP#5
   LoadConstant         r3, CP#5
   Frame                6
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#6
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 6
   StoreLocal           r5
@@ -760,7 +760,7 @@
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#42, 2
+  DynamicCall          CP#41, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
@@ -809,8 +809,8 @@
   [38] = Reserved
   [39] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [40] = Reserved
-  [41] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [42] = ICData dynamic target-name 'start', arg-desc CP#41
+  [41] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [42] = Reserved
   [43] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [44] = Reserved
 }
@@ -821,10 +821,10 @@
   LoadConstant         r2, CP#5
   LoadConstant         r3, CP#5
   Frame                7
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#6
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 5
   StoreLocal           r5
@@ -1160,7 +1160,7 @@
   LoadContextVar       0, 3
   Push                 r0
   LoadContextVar       0, 17
-  DynamicCall          CP#40, 2
+  DynamicCall          CP#39, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 3
@@ -1207,8 +1207,8 @@
   [36] = Reserved
   [37] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [38] = Reserved
-  [39] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [40] = ICData dynamic target-name 'start', arg-desc CP#39
+  [39] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [40] = Reserved
   [41] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [42] = Reserved
 }
@@ -1219,10 +1219,10 @@
   LoadConstant         r2, CP#5
   LoadConstant         r3, CP#5
   Frame                10
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#6
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 7
   StoreLocal           r5
@@ -1704,8 +1704,8 @@
   [32] = Reserved
   [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [34] = Reserved
-  [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [36] = ICData dynamic target-name 'start', arg-desc CP#35
+  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [36] = Reserved
   [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [38] = Reserved
   [39] = EndClosureFunctionScope
@@ -1713,10 +1713,10 @@
 Closure #lib::closure::'nested' async () -> dart:async::Future < dart:core::int >
 ClosureCode {
   EntryFixed           1, 4
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   AllocateContext      1, 9
   StoreLocal           r1
   Push                 r1
@@ -1792,7 +1792,7 @@
   LoadContextVar       1, 0
   Push                 r0
   LoadContextVar       1, 8
-  DynamicCall          CP#36, 2
+  DynamicCall          CP#35, 2
   Drop1
   Push                 r0
   LoadContextVar       1, 0
@@ -1807,10 +1807,10 @@
   LoadConstant         r2, CP#8
   LoadConstant         r3, CP#8
   Frame                8
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#1
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       1, 4
   StoreLocal           r5
@@ -2036,7 +2036,7 @@
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 8
-  DynamicCall          CP#36, 2
+  DynamicCall          CP#35, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
@@ -2079,8 +2079,8 @@
   [32] = Reserved
   [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [34] = Reserved
-  [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
-  [36] = ICData dynamic target-name 'start', arg-desc CP#35
+  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [36] = Reserved
   [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [38] = Reserved
 }
@@ -2091,10 +2091,10 @@
   LoadConstant         r2, CP#5
   LoadConstant         r3, CP#5
   Frame                6
-  CheckStack           0
   Push                 r0
   LoadFieldTOS         CP#6
   PopLocal             r4
+  CheckStack           0
   Push                 r4
   LoadContextVar       0, 5
   StoreLocal           r5
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index 15d60a1..a5a1c78 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -210,8 +210,7 @@
   Entry                2
   CheckStack           0
   LoadStatic           CP#0
-  EqualsNull
-  JumpIfFalse          L1
+  JumpIfNotNull        L1
   LoadStatic           CP#1
   DirectCall           CP#2, 1
   StoreLocal           r1
@@ -383,8 +382,7 @@
   Entry                2
   CheckStack           0
   LoadStatic           CP#0
-  EqualsNull
-  JumpIfFalse          L1
+  JumpIfNotNull        L1
   Allocate             CP#1
   StoreLocal           r1
   Push                 r1
@@ -583,8 +581,7 @@
   Entry                1
   CheckStack           0
   LoadStatic           CP#0
-  EqualsNull
-  JumpIfFalse          L1
+  JumpIfNotNull        L1
   LoadStatic           CP#1
   EqualsNull
   BooleanNegateTOS
@@ -597,7 +594,7 @@
   Push                 r0
   JumpIfFalse          L3
   LoadStatic           CP#1
-  DynamicCall          CP#3, 1
+  DynamicCall          CP#2, 1
   StoreStaticTOS       CP#0
 L3:
   LoadStatic           CP#0
@@ -606,8 +603,8 @@
 ConstantPool {
   [0] = StaticField #lib::VMLibraryHooks::_cachedScript (field)
   [1] = StaticField #lib::VMLibraryHooks::_computeScriptUri (field)
-  [2] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
-  [3] = ICData dynamic target-name 'call', arg-desc CP#2
+  [2] = DynamicCall 'call', ArgDesc num-args 1, num-type-args 0, names []
+  [3] = Reserved
 }
 
 Class 'Stdin', script = '#lib'
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 8da319e..76d15ca 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -72,10 +72,10 @@
 Closure #lib::simpleClosure::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
 ClosureCode {
   EntryFixed           2, 3
-  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   JumpIfUnchecked      L1
   Push                 FP[-5]
   PushConstant         CP#3
@@ -318,10 +318,10 @@
 Closure #lib::testPartialInstantiation::'foo' <dart:core::Object T> (#lib::testPartialInstantiation::Closure/0::TypeParam/0 t) -> void
 ClosureCode {
   EntryFixed           2, 3
-  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r1
+  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#3
   StoreLocal           r0
@@ -661,10 +661,10 @@
 Closure #lib::A::foo::'nested1' <dart:core::Object T5, dart:core::Object T6> () -> void
 ClosureCode {
   EntryFixed           1, 5
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
+  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#3
   StoreLocal           r0
@@ -721,10 +721,10 @@
 Closure #lib::A::foo::Closure/0::'nested2' <dart:core::Object T7, dart:core::Object T8> () -> void
 ClosureCode {
   EntryFixed           1, 5
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
+  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#3
   StoreLocal           r0
@@ -774,10 +774,10 @@
 Closure #lib::A::foo::Closure/1::'<anonymous closure>' () -> dart:core::Null
 ClosureCode {
   EntryFixed           1, 4
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
+  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#6
   PopLocal             r0
@@ -1002,10 +1002,10 @@
 Closure #lib::B::topLevel::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
 ClosureCode {
   EntryFixed           2, 4
-  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   AllocateContext      1, 2
   StoreLocal           r1
   Push                 r1
@@ -1075,10 +1075,10 @@
 Closure #lib::B::topLevel::Closure/0::'closure2' () -> void
 ClosureCode {
   EntryFixed           1, 3
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextParent
   Push                 r0
@@ -1103,10 +1103,10 @@
 Closure #lib::B::topLevel::'<anonymous closure>' () -> dart:core::Null
 ClosureCode {
   EntryFixed           1, 3
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
   Push                 r0
@@ -1269,10 +1269,10 @@
 Closure #lib::C::testForLoop::'<anonymous closure>' () -> dart:core::int
 ClosureCode {
   EntryFixed           1, 2
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#5
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextVar       1, 0
   Push                 r0
@@ -1285,10 +1285,10 @@
 Closure #lib::C::testForLoop::'<anonymous closure>' (dart:core::int ii) -> dart:core::Null
 ClosureCode {
   EntryFixed           2, 3
-  CheckStack           0
   Push                 FP[-6]
   LoadFieldTOS         CP#5
   PopLocal             r0
+  CheckStack           0
   JumpIfUnchecked      L1
   Push                 FP[-5]
   PushConstant         CP#21
@@ -1393,10 +1393,10 @@
 Closure #lib::C::testForInLoop::'<anonymous closure>' () -> dart:core::Null
 ClosureCode {
   EntryFixed           1, 3
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#7
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   Push                 r0
   LoadContextVar       0, 0
@@ -1496,10 +1496,10 @@
 Closure #lib::D::foo::'<anonymous closure>' () -> #lib::D::TypeParam/0
 ClosureCode {
   EntryFixed           1, 2
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#5
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
   ReturnTOS
@@ -1560,10 +1560,10 @@
 Closure #lib::D::bar::'<anonymous closure>' () -> dart:core::Null
 ClosureCode {
   EntryFixed           1, 4
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   AllocateClosure      CP#3
   StoreLocal           r3
   Push                 r3
@@ -1596,10 +1596,10 @@
 Closure #lib::D::bar::Closure/0::'inner' () -> dart:core::Null
 ClosureCode {
   EntryFixed           1, 2
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   PushNull
   ReturnTOS
 }
diff --git a/pkg/vm/testcases/bytecode/super_calls.dart.expect b/pkg/vm/testcases/bytecode/super_calls.dart.expect
index 3217e51..aabc371 100644
--- a/pkg/vm/testcases/bytecode/super_calls.dart.expect
+++ b/pkg/vm/testcases/bytecode/super_calls.dart.expect
@@ -179,7 +179,7 @@
   Push                 FP[-5]
   DirectCall           CP#1, 1
   PushConstant         CP#3
-  DynamicCall          CP#5, 3
+  DynamicCall          CP#4, 3
   ReturnTOS
 }
 ConstantPool {
@@ -187,8 +187,8 @@
   [1] = DirectCall '#lib::Base1::get:bar', ArgDesc num-args 1, num-type-args 0, names []
   [2] = Reserved
   [3] = ObjectRef 'param'
-  [4] = ObjectRef ArgDesc num-args 2, num-type-args 1, names []
-  [5] = ICData dynamic target-name 'call', arg-desc CP#4
+  [4] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+  [5] = Reserved
 }
 
 
@@ -413,7 +413,7 @@
   DirectCall           CP#4, 4
   DirectCall           CP#6, 2
   PushConstant         CP#8
-  DynamicCall          CP#10, 3
+  DynamicCall          CP#9, 3
   ReturnTOS
 }
 ConstantPool {
@@ -426,8 +426,8 @@
   [6] = DirectCall 'dart:core::Object::noSuchMethod', ArgDesc num-args 2, num-type-args 0, names []
   [7] = Reserved
   [8] = ObjectRef 'param'
-  [9] = ObjectRef ArgDesc num-args 2, num-type-args 1, names []
-  [10] = ICData dynamic target-name 'call', arg-desc CP#9
+  [9] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+  [10] = Reserved
 }
 
 
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index b31deef..47fd310 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -347,10 +347,10 @@
 Closure #lib::testTryCatch3::'foo' () -> void
 ClosureCode {
   EntryFixed           1, 6
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   PopLocal             r2
 Try #0 start:
@@ -383,10 +383,10 @@
 Closure #lib::testTryCatch3::'bar' () -> void
 ClosureCode {
   EntryFixed           1, 6
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   PopLocal             r2
 Try #0 start:
@@ -735,10 +735,10 @@
 Closure #lib::testTryFinally2::'foo' () -> void
 ClosureCode {
   EntryFixed           1, 2
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#7
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
   DirectCall           CP#3, 1
@@ -800,7 +800,7 @@
   DirectCall           CP#3, 1
   Drop1
   Push                 r2
-  DynamicCall          CP#19, 1
+  DynamicCall          CP#18, 1
   Drop1
   Push                 r3
   Push                 r4
@@ -813,7 +813,7 @@
   DirectCall           CP#3, 1
   Drop1
   Push                 r2
-  DynamicCall          CP#20, 1
+  DynamicCall          CP#18, 1
   Drop1
   Push                 r0
   LoadContextParent
@@ -843,17 +843,16 @@
   [15] = Reserved
   [16] = InstanceField dart:core::_Closure::_function (field)
   [17] = Reserved
-  [18] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
-  [19] = ICData dynamic target-name 'call', arg-desc CP#18
-  [20] = ICData dynamic target-name 'call', arg-desc CP#18
+  [18] = DynamicCall 'call', ArgDesc num-args 1, num-type-args 0, names []
+  [19] = Reserved
 }
 Closure #lib::testTryFinally3::'<anonymous closure>' () -> dart:core::int
 ClosureCode {
   EntryFixed           1, 6
-  CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
+  CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
   DirectCall           CP#3, 1
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index 9804186..af14940 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -735,7 +735,7 @@
       : super #lib::G::•()
       ;
     method foo8<generic-covariant-impl Q extends #lib::H::T* = #lib::H::T*>(#lib::H::foo8::Q* a, dart.core::int* b, generic-covariant-impl #lib::H::T* c) → void {}
-    forwarding-stub method foo7<generic-covariant-impl Q extends #lib::H::T*>(#lib::H::foo7::Q a, covariant dart.core::num* b, generic-covariant-impl #lib::H::T* c) → void
+    forwarding-stub method foo7<generic-covariant-impl Q extends #lib::H::T*>(#lib::H::foo7::Q* a, covariant dart.core::num* b, generic-covariant-impl #lib::H::T* c) → void
       return super.{#lib::G::foo7}<#lib::H::foo7::Q*>(a, b, c);
   }
   static field dart.core::List<dart.core::Iterable<dynamic>*>* globalVar;
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart
new file mode 100644
index 0000000..5e77376
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+smiLiteral() => 42;
+
+intLiteral() => 0x8000000000000000;
+
+strLiteral() => 'abc';
+
+const _constList1 = [1, 2, 3];
+indexingIntoConstantList1(int i) => _constList1[i];
+
+const _constList2 = ['hi', 33, null, -5];
+indexingIntoConstantList2(int i) => _constList2[i];
+
+main() {}
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
new file mode 100644
index 0000000..39e0f94
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
@@ -0,0 +1,25 @@
+------------ #lib::smiLiteral ------------
+
+RESULT: _T (dart.core::_Smi)
+------------ #lib::intLiteral ------------
+
+RESULT: _T (dart.core::int*)+
+------------ #lib::strLiteral ------------
+
+RESULT: _T (dart.core::_OneByteString)
+------------ #lib::indexingIntoConstantList1 ------------
+%i = _Parameter #0 [_T (dart.core::int*)+?]
+RESULT: _T (dart.core::_Smi)
+------------ #lib::indexingIntoConstantList2 ------------
+%i = _Parameter #0 [_T (dart.core::int*)+?]
+t1 = _Join [dart.core::Object*] (_T (dart.core::_OneByteString), _T (dart.core::_Smi), _T {}?)
+RESULT: t1
+------------ #lib::main ------------
+
+RESULT: _T {}?
+------------ #lib::_constList1 ------------
+
+RESULT: _T (dart.core::_ImmutableList)
+------------ #lib::_constList2 ------------
+
+RESULT: _T (dart.core::_ImmutableList)
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart
new file mode 100644
index 0000000..84a66fd
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart
@@ -0,0 +1,11 @@
+// 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.
+
+// Test that an abstract class with no members is retained if marked as an
+// entry-point.
+
+@pragma("vm:entry-point")
+abstract class AbstractEmptyClass {}
+
+main() {}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect
new file mode 100644
index 0000000..3864b4c
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect
@@ -0,0 +1,8 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+@#C3
+abstract class AbstractEmptyClass extends core::Object {
+}
+static method main() → dynamic {}
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index b4b0668..cd25650 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,14 @@
 # Changelog
 
+## 1.2.0
+- Support service protocol version 3.27:
+  - Added `getCpuSamples` and `clearCpuSamples` methods
+  - Added `CpuSamples`, `CpuSample`, and `ProfileFunction` classes.
+
+## 1.1.2
+- Fixed issue where `closureFunction` and `closureContext` were only expected in
+  `Instance` objects rather than `InstanceRef`.
+
 ## 1.1.1
 - Fixed issue serializing list arguments for certain VM service methods.
   - Issue #37872
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index df11b53..baaad58 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -28,6 +28,11 @@
   return obj;
 }
 
+dynamic assertDynamic(dynamic obj) {
+  assertNotNull(obj);
+  return obj;
+}
+
 List<int> assertListOfInt(List<int> list) {
   for (int elem in list) {
     assertInt(elem);
@@ -429,6 +434,36 @@
   return list;
 }
 
+vms.CpuSamples assertCpuSamples(vms.CpuSamples obj) {
+  assertNotNull(obj);
+  assertString(obj.type);
+  assertInt(obj.samplePeriod);
+  assertInt(obj.maxStackDepth);
+  assertInt(obj.sampleCount);
+  assertInt(obj.timeSpan);
+  assertInt(obj.timeOriginMicros);
+  assertInt(obj.timeExtentMicros);
+  assertInt(obj.pid);
+  assertListOfProfileFunction(obj.functions);
+  assertListOfCpuSample(obj.samples);
+  return obj;
+}
+
+vms.CpuSample assertCpuSample(vms.CpuSample obj) {
+  assertNotNull(obj);
+  assertInt(obj.tid);
+  assertInt(obj.timestamp);
+  assertListOfInt(obj.stack);
+  return obj;
+}
+
+List<vms.CpuSample> assertListOfCpuSample(List<vms.CpuSample> list) {
+  for (vms.CpuSample elem in list) {
+    assertCpuSample(elem);
+  }
+  return list;
+}
+
 vms.ErrorRef assertErrorRef(vms.ErrorRef obj) {
   assertNotNull(obj);
   assertString(obj.type);
@@ -773,6 +808,12 @@
   return list;
 }
 
+vms.NativeFunction assertNativeFunction(vms.NativeFunction obj) {
+  assertNotNull(obj);
+  assertString(obj.name);
+  return obj;
+}
+
 vms.NullValRef assertNullValRef(vms.NullValRef obj) {
   assertNotNull(obj);
   assertString(obj.type);
@@ -821,6 +862,24 @@
   return obj;
 }
 
+vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) {
+  assertNotNull(obj);
+  assertString(obj.kind);
+  assertInt(obj.inclusiveTicks);
+  assertInt(obj.exclusiveTicks);
+  assertString(obj.resolvedUrl);
+  assertDynamic(obj.function);
+  return obj;
+}
+
+List<vms.ProfileFunction> assertListOfProfileFunction(
+    List<vms.ProfileFunction> list) {
+  for (vms.ProfileFunction elem in list) {
+    assertProfileFunction(elem);
+  }
+  return list;
+}
+
 vms.ReloadReport assertReloadReport(vms.ReloadReport obj) {
   assertNotNull(obj);
   assertString(obj.type);
diff --git a/pkg/vm_service/example/vm_service_tester.dart b/pkg/vm_service/example/vm_service_tester.dart
index 5d1f819..f02be8e 100644
--- a/pkg/vm_service/example/vm_service_tester.dart
+++ b/pkg/vm_service/example/vm_service_tester.dart
@@ -51,6 +51,7 @@
 
     await new Future.delayed(new Duration(milliseconds: 500));
 
+    // ignore: deprecated_member_use_from_same_package
     serviceClient = await vmServiceConnect(host, port, log: new StdoutLog());
 
     print('socket connected');
@@ -126,7 +127,11 @@
     IsolateRef isolateRef = isolates.first;
     print(await serviceClient.resume(isolateRef.id));
 
+    print('waiting for client to shut down...');
     serviceClient.dispose();
+
+    await serviceClient.onDone;
+    print('service client shut down');
   });
 }
 
@@ -158,9 +163,10 @@
   });
   await serviceClient.registerService(serviceName, serviceAlias);
   VmService otherClient =
+      // ignore: deprecated_member_use_from_same_package
       await vmServiceConnect(host, port, log: new StdoutLog());
   Completer completer = new Completer();
-  otherClient.onEvent('_Service').listen((e) async {
+  otherClient.onEvent('Service').listen((e) async {
     if (e.service == serviceName && e.kind == EventKind.kServiceRegistered) {
       assert(e.alias == serviceAlias);
       Response response = await serviceClient.callMethod(
@@ -171,8 +177,9 @@
       completer.complete();
     }
   });
-  await otherClient.streamListen('_Service');
+  await otherClient.streamListen('Service');
   await completer.future;
+  otherClient.dispose();
 }
 
 Future testScriptParse(IsolateRef isolateRef) async {
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index 4fef6d5..5f9d198 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -3,6 +3,7 @@
 src/org/dartlang/vm/service/VmService.java
 src/org/dartlang/vm/service/consumer/AllocationProfileConsumer.java
 src/org/dartlang/vm/service/consumer/BreakpointConsumer.java
+src/org/dartlang/vm/service/consumer/CpuSamplesConsumer.java
 src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
 src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
 src/org/dartlang/vm/service/consumer/FlagListConsumer.java
@@ -37,6 +38,8 @@
 src/org/dartlang/vm/service/element/Context.java
 src/org/dartlang/vm/service/element/ContextElement.java
 src/org/dartlang/vm/service/element/ContextRef.java
+src/org/dartlang/vm/service/element/CpuSample.java
+src/org/dartlang/vm/service/element/CpuSamples.java
 src/org/dartlang/vm/service/element/ErrorKind.java
 src/org/dartlang/vm/service/element/ErrorObj.java
 src/org/dartlang/vm/service/element/ErrorRef.java
@@ -67,10 +70,12 @@
 src/org/dartlang/vm/service/element/MapAssociation.java
 src/org/dartlang/vm/service/element/MemoryUsage.java
 src/org/dartlang/vm/service/element/Message.java
+src/org/dartlang/vm/service/element/NativeFunction.java
 src/org/dartlang/vm/service/element/Null.java
 src/org/dartlang/vm/service/element/NullRef.java
 src/org/dartlang/vm/service/element/Obj.java
 src/org/dartlang/vm/service/element/ObjRef.java
+src/org/dartlang/vm/service/element/ProfileFunction.java
 src/org/dartlang/vm/service/element/ReloadReport.java
 src/org/dartlang/vm/service/element/Response.java
 src/org/dartlang/vm/service/element/RetainingObject.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index 55a8c99..c025869 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.26
+version=3.27
diff --git a/pkg/vm_service/lib/vm_service.dart b/pkg/vm_service/lib/vm_service.dart
index 0030b6b..2838a4e 100644
--- a/pkg/vm_service/lib/vm_service.dart
+++ b/pkg/vm_service/lib/vm_service.dart
@@ -17,7 +17,7 @@
 
 export 'src/service_extension_registry.dart' show ServiceExtensionRegistry;
 
-const String vmServiceVersion = '3.26.0';
+const String vmServiceVersion = '3.27.0';
 
 /// @optional
 const String optional = 'optional';
@@ -102,6 +102,8 @@
   '@Context': ContextRef.parse,
   'Context': Context.parse,
   'ContextElement': ContextElement.parse,
+  'CpuSamples': CpuSamples.parse,
+  'CpuSample': CpuSample.parse,
   '@Error': ErrorRef.parse,
   'Error': Error.parse,
   'Event': Event.parse,
@@ -127,10 +129,12 @@
   'MapAssociation': MapAssociation.parse,
   'MemoryUsage': MemoryUsage.parse,
   'Message': Message.parse,
+  'NativeFunction': NativeFunction.parse,
   '@Null': NullValRef.parse,
   'Null': NullVal.parse,
   '@Object': ObjRef.parse,
   'Object': Obj.parse,
+  'ProfileFunction': ProfileFunction.parse,
   'ReloadReport': ReloadReport.parse,
   'RetainingObject': RetainingObject.parse,
   'RetainingPath': RetainingPath.parse,
@@ -161,11 +165,13 @@
   'addBreakpoint': const ['Breakpoint'],
   'addBreakpointWithScriptUri': const ['Breakpoint'],
   'addBreakpointAtEntry': const ['Breakpoint'],
+  'clearCpuSamples': const ['Success'],
   'clearVMTimeline': const ['Success'],
   'invoke': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
   'evaluate': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
   'evaluateInFrame': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
   'getAllocationProfile': const ['AllocationProfile'],
+  'getCpuSamples': const ['CpuSamples'],
   'getFlagList': const ['FlagList'],
   'getInboundReferences': const ['InboundReferences', 'Sentinel'],
   'getInstances': const ['InstanceSet'],
@@ -283,6 +289,11 @@
   /// Note that breakpoints are added and removed on a per-isolate basis.
   Future<Breakpoint> addBreakpointAtEntry(String isolateId, String functionId);
 
+  /// Clears all CPU profiling samples.
+  ///
+  /// See [Success].
+  Future<Success> clearCpuSamples(String isolateId);
+
   /// Clears all VM timeline events.
   ///
   /// See [Success].
@@ -410,6 +421,16 @@
   Future<AllocationProfile> getAllocationProfile(String isolateId,
       {bool reset, bool gc});
 
+  /// The `getCpuSamples` RPC is used to retrieve samples collected by the CPU
+  /// profiler. Only samples collected in the time range `[timeOriginMicros,
+  /// timeOriginMicros + timeExtentMicros]` will be reported.
+  ///
+  /// If the profiler is disabled, an error response will be returned.
+  ///
+  /// See [CpuSamples].
+  Future<CpuSamples> getCpuSamples(
+      String isolateId, int timeOriginMicros, int timeExtentMicros);
+
   /// The `getFlagList` RPC returns a list of all command line flags in the VM
   /// along with their current values.
   ///
@@ -921,6 +942,11 @@
             params['functionId'],
           );
           break;
+        case 'clearCpuSamples':
+          response = await _serviceImplementation.clearCpuSamples(
+            params['isolateId'],
+          );
+          break;
         case 'clearVMTimeline':
           response = await _serviceImplementation.clearVMTimeline();
           break;
@@ -958,6 +984,13 @@
             gc: params['gc'],
           );
           break;
+        case 'getCpuSamples':
+          response = await _serviceImplementation.getCpuSamples(
+            params['isolateId'],
+            params['timeOriginMicros'],
+            params['timeExtentMicros'],
+          );
+          break;
         case 'getFlagList':
           response = await _serviceImplementation.getFlagList();
           break;
@@ -1199,6 +1232,8 @@
   StreamController<String> _onReceive =
       new StreamController.broadcast(sync: true);
 
+  final Completer _onDoneCompleter = new Completer();
+
   Map<String, StreamController<Event>> _eventControllers = {};
 
   StreamController<Event> _getEventController(String eventName) {
@@ -1212,13 +1247,23 @@
 
   DisposeHandler _disposeHandler;
 
-  VmService(Stream<dynamic> /*String|List<int>*/ inStream,
-      void writeMessage(String message),
-      {Log log, DisposeHandler disposeHandler}) {
-    _streamSub = inStream.listen(_processMessage);
+  VmService(
+    Stream<dynamic> /*String|List<int>*/ inStream,
+    void writeMessage(String message), {
+    Log log,
+    DisposeHandler disposeHandler,
+    Future streamClosed,
+  }) {
+    _streamSub = inStream.listen(_processMessage,
+        onDone: () => _onDoneCompleter.complete());
     _writeMessage = writeMessage;
     _log = log == null ? new _NullLog() : log;
     _disposeHandler = disposeHandler;
+    streamClosed?.then((_) {
+      if (!_onDoneCompleter.isCompleted) {
+        _onDoneCompleter.complete();
+      }
+    });
   }
 
   @override
@@ -1294,6 +1339,11 @@
   }
 
   @override
+  Future<Success> clearCpuSamples(String isolateId) {
+    return _call('clearCpuSamples', {'isolateId': isolateId});
+  }
+
+  @override
   Future<Success> clearVMTimeline() => _call('clearVMTimeline');
 
   @override
@@ -1374,6 +1424,16 @@
   }
 
   @override
+  Future<CpuSamples> getCpuSamples(
+      String isolateId, int timeOriginMicros, int timeExtentMicros) {
+    return _call('getCpuSamples', {
+      'isolateId': isolateId,
+      'timeOriginMicros': timeOriginMicros,
+      'timeExtentMicros': timeExtentMicros
+    });
+  }
+
+  @override
   Future<FlagList> getFlagList() => _call('getFlagList');
 
   @override
@@ -1626,9 +1686,16 @@
   void dispose() {
     _streamSub.cancel();
     _completers.values.forEach((c) => c.completeError('disposed'));
-    if (_disposeHandler != null) _disposeHandler();
+    if (_disposeHandler != null) {
+      _disposeHandler();
+    }
+    if (!_onDoneCompleter.isCompleted) {
+      _onDoneCompleter.complete();
+    }
   }
 
+  Future get onDone => _onDoneCompleter.future;
+
   Future<T> _call<T>(String method, [Map args]) {
     String id = '${++_id}';
     Completer<T> completer = new Completer<T>();
@@ -2713,6 +2780,144 @@
   String toString() => '[ContextElement value: ${value}]';
 }
 
+/// See [getCpuSamples] and [CpuSample].
+class CpuSamples extends Response {
+  static CpuSamples parse(Map<String, dynamic> json) =>
+      json == null ? null : new CpuSamples._fromJson(json);
+
+  /// The sampling rate for the profiler in microseconds.
+  int samplePeriod;
+
+  /// The maximum possible stack depth for samples.
+  int maxStackDepth;
+
+  /// The number of samples returned.
+  int sampleCount;
+
+  /// The timespan the set of returned samples covers, in microseconds.
+  int timeSpan;
+
+  /// The start of the period of time in which the returned samples were
+  /// collected.
+  int timeOriginMicros;
+
+  /// The duration of time covered by the returned samples.
+  int timeExtentMicros;
+
+  /// The process ID for the VM.
+  int pid;
+
+  /// A list of functions seen in the relevant samples. These references can be
+  /// looked up using the indicies provided in a `CpuSample` `stack` to
+  /// determine which function was on the stack.
+  List<ProfileFunction> functions;
+
+  /// A list of samples collected in the range `[timeOriginMicros,
+  /// timeOriginMicros + timeExtentMicros]`
+  List<CpuSample> samples;
+
+  CpuSamples();
+
+  CpuSamples._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+    samplePeriod = json['samplePeriod'];
+    maxStackDepth = json['maxStackDepth'];
+    sampleCount = json['sampleCount'];
+    timeSpan = json['timeSpan'];
+    timeOriginMicros = json['timeOriginMicros'];
+    timeExtentMicros = json['timeExtentMicros'];
+    pid = json['pid'];
+    functions = new List<ProfileFunction>.from(
+        createServiceObject(json['functions'], const ['ProfileFunction']));
+    samples = new List<CpuSample>.from(
+        createServiceObject(json['samples'], const ['CpuSample']));
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json['type'] = 'CpuSamples';
+    json.addAll({
+      'samplePeriod': samplePeriod,
+      'maxStackDepth': maxStackDepth,
+      'sampleCount': sampleCount,
+      'timeSpan': timeSpan,
+      'timeOriginMicros': timeOriginMicros,
+      'timeExtentMicros': timeExtentMicros,
+      'pid': pid,
+      'functions': functions.map((f) => f.toJson()).toList(),
+      'samples': samples.map((f) => f.toJson()).toList(),
+    });
+    return json;
+  }
+
+  String toString() => '[CpuSamples]';
+}
+
+/// See [getCpuSamples] and [CpuSamples].
+class CpuSample {
+  static CpuSample parse(Map<String, dynamic> json) =>
+      json == null ? null : new CpuSample._fromJson(json);
+
+  /// The thread ID representing the thread on which this sample was collected.
+  int tid;
+
+  /// The time this sample was collected in microseconds.
+  int timestamp;
+
+  /// The name of VM tag set when this sample was collected. Omitted if the VM
+  /// tag for the sample is not considered valid.
+  @optional
+  String vmTag;
+
+  /// The name of the User tag set when this sample was collected. Omitted if no
+  /// User tag was set when this sample was collected.
+  @optional
+  String userTag;
+
+  /// Provided and set to true if the sample's stack was truncated. This can
+  /// happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
+  /// response.
+  @optional
+  bool truncated;
+
+  /// The call stack at the time this sample was collected. The stack is to be
+  /// interpreted as top to bottom. Each element in this array is a key into the
+  /// `functions` array in `CpuSamples`.
+  ///
+  /// Example:
+  ///
+  /// `functions[stack[0]] = @Function(bar())` `functions[stack[1]] =
+  /// @Function(foo())` `functions[stack[2]] = @Function(main())`
+  List<int> stack;
+
+  CpuSample();
+
+  CpuSample._fromJson(Map<String, dynamic> json) {
+    tid = json['tid'];
+    timestamp = json['timestamp'];
+    vmTag = json['vmTag'];
+    userTag = json['userTag'];
+    truncated = json['truncated'];
+    stack = new List<int>.from(json['stack']);
+  }
+
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json.addAll({
+      'tid': tid,
+      'timestamp': timestamp,
+      'stack': stack.map((f) => f).toList(),
+    });
+    _setIfNotNull(json, 'vmTag', vmTag);
+    _setIfNotNull(json, 'userTag', userTag);
+    _setIfNotNull(json, 'truncated', truncated);
+    return json;
+  }
+
+  String toString() =>
+      '[CpuSample tid: ${tid}, timestamp: ${timestamp}, stack: ${stack}]';
+}
+
 /// `ErrorRef` is a reference to an `Error`.
 class ErrorRef extends ObjRef {
   static ErrorRef parse(Map<String, dynamic> json) =>
@@ -3492,6 +3697,20 @@
   @optional
   InstanceRef pattern;
 
+  /// The function associated with a Closure instance.
+  ///
+  /// Provided for instance kinds:
+  ///  - Closure
+  @optional
+  FuncRef closureFunction;
+
+  /// The context associated with a Closure instance.
+  ///
+  /// Provided for instance kinds:
+  ///  - Closure
+  @optional
+  ContextRef closureContext;
+
   InstanceRef();
 
   InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -3505,6 +3724,10 @@
     parameterizedClass =
         createServiceObject(json['parameterizedClass'], const ['ClassRef']);
     pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
+    closureFunction =
+        createServiceObject(json['closureFunction'], const ['FuncRef']);
+    closureContext =
+        createServiceObject(json['closureContext'], const ['ContextRef']);
   }
 
   @override
@@ -3523,6 +3746,8 @@
     _setIfNotNull(json, 'typeClass', typeClass?.toJson());
     _setIfNotNull(json, 'parameterizedClass', parameterizedClass?.toJson());
     _setIfNotNull(json, 'pattern', pattern?.toJson());
+    _setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
+    _setIfNotNull(json, 'closureContext', closureContext?.toJson());
     return json;
   }
 
@@ -3696,20 +3921,6 @@
   @optional
   String bytes;
 
-  /// The function associated with a Closure instance.
-  ///
-  /// Provided for instance kinds:
-  ///  - Closure
-  @optional
-  FuncRef closureFunction;
-
-  /// The context associated with a Closure instance.
-  ///
-  /// Provided for instance kinds:
-  ///  - Closure
-  @optional
-  ContextRef closureContext;
-
   /// The referent of a MirrorReference instance.
   ///
   /// Provided for instance kinds:
@@ -3816,10 +4027,6 @@
         : new List<MapAssociation>.from(
             _createSpecificObject(json['associations'], MapAssociation.parse));
     bytes = json['bytes'];
-    closureFunction =
-        createServiceObject(json['closureFunction'], const ['FuncRef']);
-    closureContext =
-        createServiceObject(json['closureContext'], const ['ContextRef']);
     mirrorReferent =
         createServiceObject(json['mirrorReferent'], const ['InstanceRef']);
     pattern = json['pattern'];
@@ -3859,8 +4066,6 @@
     _setIfNotNull(
         json, 'associations', associations?.map((f) => f?.toJson())?.toList());
     _setIfNotNull(json, 'bytes', bytes);
-    _setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
-    _setIfNotNull(json, 'closureContext', closureContext?.toJson());
     _setIfNotNull(json, 'mirrorReferent', mirrorReferent?.toJson());
     _setIfNotNull(json, 'pattern', pattern);
     _setIfNotNull(json, 'isCaseSensitive', isCaseSensitive);
@@ -4491,6 +4696,32 @@
       'size: ${size}]';
 }
 
+/// A `NativeFunction` object is used to represent native functions in profiler
+/// samples. See [CpuSamples];
+class NativeFunction {
+  static NativeFunction parse(Map<String, dynamic> json) =>
+      json == null ? null : new NativeFunction._fromJson(json);
+
+  /// The name of the native function this object represents.
+  String name;
+
+  NativeFunction();
+
+  NativeFunction._fromJson(Map<String, dynamic> json) {
+    name = json['name'];
+  }
+
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json.addAll({
+      'name': name,
+    });
+    return json;
+  }
+
+  String toString() => '[NativeFunction name: ${name}]';
+}
+
 /// `NullValRef` is a reference to an a `NullVal`.
 class NullValRef extends InstanceRef {
   static NullValRef parse(Map<String, dynamic> json) =>
@@ -4666,6 +4897,57 @@
   String toString() => '[Obj type: ${type}, id: ${id}]';
 }
 
+/// A `ProfileFunction` contains profiling information about a Dart or native
+/// function.
+///
+/// See [CpuSamples].
+class ProfileFunction {
+  static ProfileFunction parse(Map<String, dynamic> json) =>
+      json == null ? null : new ProfileFunction._fromJson(json);
+
+  /// The kind of function this object represents.
+  String kind;
+
+  /// The number of times function appeared on the stack during sampling events.
+  int inclusiveTicks;
+
+  /// The number of times function appeared on the top of the stack during
+  /// sampling events.
+  int exclusiveTicks;
+
+  /// The resolved URL for the script containing function.
+  String resolvedUrl;
+
+  /// The function captured during profiling.
+  dynamic function;
+
+  ProfileFunction();
+
+  ProfileFunction._fromJson(Map<String, dynamic> json) {
+    kind = json['kind'];
+    inclusiveTicks = json['inclusiveTicks'];
+    exclusiveTicks = json['exclusiveTicks'];
+    resolvedUrl = json['resolvedUrl'];
+    function = createServiceObject(json['function'], const ['dynamic']);
+  }
+
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json.addAll({
+      'kind': kind,
+      'inclusiveTicks': inclusiveTicks,
+      'exclusiveTicks': exclusiveTicks,
+      'resolvedUrl': resolvedUrl,
+      'function': function.toJson(),
+    });
+    return json;
+  }
+
+  String toString() => '[ProfileFunction ' //
+      'kind: ${kind}, inclusiveTicks: ${inclusiveTicks}, exclusiveTicks: ${exclusiveTicks}, ' //
+      'resolvedUrl: ${resolvedUrl}, function: ${function}]';
+}
+
 class ReloadReport extends Response {
   static ReloadReport parse(Map<String, dynamic> json) =>
       json == null ? null : new ReloadReport._fromJson(json);
diff --git a/pkg/vm_service/lib/vm_service_io.dart b/pkg/vm_service/lib/vm_service_io.dart
index f7aa745..c95d0ac 100644
--- a/pkg/vm_service/lib/vm_service_io.dart
+++ b/pkg/vm_service/lib/vm_service_io.dart
@@ -7,20 +7,42 @@
 
 import 'vm_service.dart';
 
+@Deprecated('Prefer vmServiceConnectUri')
 Future<VmService> vmServiceConnect(String host, int port, {Log log}) async {
-  WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
-  StreamController<String> controller = new StreamController();
-  socket.listen((data) => controller.add(data));
+  final WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
+  final StreamController<dynamic> controller = new StreamController();
+  final Completer streamClosedCompleter = new Completer();
+
+  socket.listen(
+    (data) => controller.add(data),
+    onDone: () => streamClosedCompleter.complete(),
+  );
+
   return new VmService(
-      controller.stream, (String message) => socket.add(message),
-      log: log, disposeHandler: () => socket.close());
+    controller.stream,
+    (String message) => socket.add(message),
+    log: log,
+    disposeHandler: () => socket.close(),
+    streamClosed: streamClosedCompleter.future,
+  );
 }
 
+/// Connect to the given uri and return a new [VmService] instance.
 Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
-  WebSocket socket = await WebSocket.connect(wsUri);
-  StreamController<String> controller = new StreamController();
-  socket.listen((data) => controller.add(data));
+  final WebSocket socket = await WebSocket.connect(wsUri);
+  final StreamController<dynamic> controller = new StreamController();
+  final Completer streamClosedCompleter = new Completer();
+
+  socket.listen(
+    (data) => controller.add(data),
+    onDone: () => streamClosedCompleter.complete(),
+  );
+
   return new VmService(
-      controller.stream, (String message) => socket.add(message),
-      log: log, disposeHandler: () => socket.close());
+    controller.stream,
+    (String message) => socket.add(message),
+    log: log,
+    disposeHandler: () => socket.close(),
+    streamClosed: streamClosedCompleter.future,
+  );
 }
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 244e9f6..d5e62e2 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
-version: 1.1.1
+version: 1.2.0
 
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
new file mode 100644
index 0000000..4d52ce4
--- /dev/null
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/test_helper.dart';
+
+printSync() {
+  print('sync'); // Line 11
+}
+
+printAsync() async {
+  await null;
+  print('async'); // Line 16
+}
+
+printAsyncStar() async* {
+  await null;
+  print('async*'); // Line 21
+}
+
+printSyncStar() sync* {
+  print('sync*'); // Line 25
+}
+
+var testerReady = false;
+testeeDo() {
+  // We block here rather than allowing the isolate to enter the
+  // paused-on-exit state before the tester gets a chance to set
+  // the breakpoints because we need the event loop to remain
+  // operational for the async bodies to run.
+  print('testee waiting');
+  while (!testerReady) {}
+
+  printSync();
+  final future = printAsync();
+  final stream = printAsyncStar();
+  final iterator = printSyncStar();
+
+  print('middle'); // Line 42
+
+  future.then((v) => print(v));
+  stream.toList();
+  iterator.toList();
+}
+
+Future testAsync(VmService service, IsolateRef isolateRef) async {
+  final isolate = await service.getIsolate(isolateRef.id);
+  final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+  final script = lib.scripts[0];
+
+  final bp1 = await service.addBreakpoint(isolate.id, script.id, 11);
+  expect(bp1, isNotNull);
+  expect(bp1 is Breakpoint, isTrue);
+
+  final bp2 = await service.addBreakpoint(isolate.id, script.id, 16);
+  expect(bp2, isNotNull);
+  expect(bp2 is Breakpoint, isTrue);
+
+  final bp3 = await service.addBreakpoint(isolate.id, script.id, 21);
+  expect(bp3, isNotNull);
+  expect(bp3 is Breakpoint, isTrue);
+
+  final bp4 = await service.addBreakpoint(isolate.id, script.id, 25);
+  expect(bp4, isNotNull);
+  expect(bp4 is Breakpoint, isTrue);
+
+  final bp5 = await service.addBreakpoint(isolate.id, script.id, 42);
+  expect(bp5, isNotNull);
+  expect(bp5 is Breakpoint, isTrue);
+
+  final hits = <Breakpoint>[];
+  await service.streamListen(EventStreams.kDebug);
+
+  // ignore: unawaited_futures
+  service
+      .evaluate(isolate.id, lib.id, 'testerReady = true')
+      .then((result) async {
+    result = await service.getObject(isolate.id, result.id);
+    print(result);
+    expect((result as Instance).valueAsString, equals('true'));
+  });
+
+  final stream = service.onDebugEvent;
+  await for (Event event in stream) {
+    if (event.kind == EventKind.kPauseBreakpoint) {
+      assert(event.pauseBreakpoints.isNotEmpty);
+      final bp = event.pauseBreakpoints.first;
+      hits.add(bp);
+      await service.resume(isolate.id);
+
+      if (hits.length == 5) break;
+    }
+  }
+
+  expect(hits, equals([bp1, bp5, bp4, bp2, bp3]));
+}
+
+final tests = <IsolateTest>[testAsync];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testeeDo);
diff --git a/pkg/vm_service/test/async_next_test.dart b/pkg/vm_service/test/async_next_test.dart
new file mode 100644
index 0000000..1d7387f
--- /dev/null
+++ b/pkg/vm_service/test/async_next_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 18;
+const int LINE_B = 19;
+const int LINE_C = 20;
+
+foo() async {}
+
+doAsync(stop) async {
+  if (stop) debugger();
+  await foo(); // Line A.
+  await foo(); // Line B.
+  await foo(); // Line C.
+  return null;
+}
+
+testMain() {
+  // With two runs of doAsync floating around, async step should only cause
+  // us to stop in the run we started in.
+  doAsync(false);
+  doAsync(true);
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver, // foo()
+  asyncNext,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  stepOver, // foo()
+  asyncNext,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_scope_test.dart b/pkg/vm_service/test/async_scope_test.dart
new file mode 100644
index 0000000..80813b6
--- /dev/null
+++ b/pkg/vm_service/test/async_scope_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:developer';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 20;
+const int LINE_B = 26;
+
+foo() {}
+
+doAsync(param1) async {
+  var local1 = param1 + 1;
+  foo(); // Line A.
+  await local1;
+}
+
+doAsyncStar(param2) async* {
+  var local2 = param2 + 1;
+  foo(); // Line B.
+  yield local2;
+}
+
+testeeDo() {
+  debugger();
+
+  doAsync(1).then((_) {
+    doAsyncStar(1).listen((_) {});
+  });
+}
+
+Future<void> checkAsyncVarDescriptors(
+    VmService service, IsolateRef isolateRef) async {
+  final stack = await service.getStack(isolateRef.id);
+  expect(stack.frames.length, greaterThanOrEqualTo(1));
+  final frame = stack.frames[0];
+  final vars = frame.vars.map((v) => v.name).join(' ');
+  expect(vars, 'param1 local1'); // no :async_op et al
+}
+
+Future checkAsyncStarVarDescriptors(
+    VmService service, IsolateRef isolateRef) async {
+  final stack = await service.getStack(isolateRef.id);
+  expect(stack.frames.length, greaterThanOrEqualTo(1));
+  final frame = stack.frames[0];
+  final vars = frame.vars.map((v) => v.name).join(' ');
+  expect(vars, 'param2 local2'); // no :async_op et al
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint, // debugger()
+  setBreakpointAtLine(LINE_A),
+  setBreakpointAtLine(LINE_B),
+  resumeIsolate,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  checkAsyncVarDescriptors,
+  resumeIsolate,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  checkAsyncStarVarDescriptors,
+  resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testeeDo);
diff --git a/pkg/vm_service/test/async_single_step_exception_test.dart b/pkg/vm_service/test/async_single_step_exception_test.dart
new file mode 100644
index 0000000..e36b6d8
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_exception_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 18;
+const LINE_B = 19;
+const LINE_C = 24;
+const LINE_D = 26;
+const LINE_E = 29;
+const LINE_F = 32;
+const LINE_G = 34;
+
+helper() async {
+  print('helper'); // LINE_A.
+  throw 'a'; // LINE_B.
+}
+
+testMain() async {
+  debugger();
+  print('mmmmm'); // LINE_C.
+  try {
+    await helper(); // LINE_D.
+  } catch (e) {
+    // arrive here on error.
+    print('error: $e'); // LINE_E.
+  } finally {
+    // arrive here in both cases.
+    print('foo'); // LINE_F.
+  }
+  print('z'); // LINE_G.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C), // print mmmm
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D), // await helper
+  stepInto,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A), // print helper
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B), // throw a
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(20), // } (weird dispatching)
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D), // await helper (weird dispatching)
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_E), // print(error)
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_E), // print(error) (weird finally dispatching)
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_F), // print(foo)
+  smartNext,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_G), // print(z)
+  resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_single_step_into_test.dart b/pkg/vm_service/test/async_single_step_into_test.dart
new file mode 100644
index 0000000..6d1072c
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_into_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 15;
+const LINE_B = 16;
+const LINE_C = 21;
+const LINE_D = 22;
+
+helper() async {
+  print('helper'); // LINE_A.
+  print('foobar'); // LINE_B.
+}
+
+testMain() {
+  debugger();
+  print('mmmmm'); // LINE_C.
+  helper(); // LINE_D.
+  print('z');
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_single_step_out_test.dart b/pkg/vm_service/test/async_single_step_out_test.dart
new file mode 100644
index 0000000..1b8eac7
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_out_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 16;
+const LINE_B = 17;
+const LINE_C = 22;
+const LINE_D = 23;
+const LINE_E = 24;
+
+helper() async {
+  print('helper'); // LINE_A.
+  return null; // LINE_B.
+}
+
+testMain() async {
+  debugger();
+  print('mmmmm'); // LINE_C.
+  await helper(); // LINE_D.
+  print('z'); // LINE_E.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C), // print mmmm
+  stepOver,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D), // await helper
+  stepInto,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A), // print.
+  stepOver,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B), // return null.
+  stepInto, // exit helper via a single step.
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(18), // return null (weird dispatching)
+  stepInto, // exit helper via a single step.
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(23), // await helper (weird dispatching)
+  smartNext,
+
+  hasStoppedAtBreakpoint, //19
+  stoppedAtLine(LINE_E), // arrive after the await.
+  resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_star_single_step_into_test.dart b/pkg/vm_service/test/async_star_single_step_into_test.dart
new file mode 100644
index 0000000..bb0f8da
--- /dev/null
+++ b/pkg/vm_service/test/async_star_single_step_into_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 17;
+const LINE_B = 18;
+const LINE_C = 22;
+const LINE_D = 26;
+const LINE_E = 32;
+const LINE_F = 33;
+
+foobar() async* {
+  yield 1; // LINE_A.
+  yield 2; // LINE_B.
+}
+
+helper() async {
+  print('helper'); // LINE_C.
+  // ignore: unused_local_variable
+  await for (var i in foobar()) {
+    debugger();
+    print('loop'); // LINE_D.
+  }
+}
+
+testMain() {
+  debugger();
+  print('mmmmm'); // LINE_E.
+  helper(); // LINE_F.
+  print('z');
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_E),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_F),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  // Resume here to exit the generator function.
+  // TODO(johnmccutchan): Implement support for step-out of async functions.
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_star_step_out_test.dart b/pkg/vm_service/test/async_star_step_out_test.dart
new file mode 100644
index 0000000..c1a532e
--- /dev/null
+++ b/pkg/vm_service/test/async_star_step_out_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 20;
+const LINE_B = 21;
+const LINE_C = 25;
+const LINE_D = 29;
+const LINE_E = 36;
+const LINE_F = 37;
+const LINE_G = 38;
+const LINE_H = 27;
+const LINE_I = 31;
+
+foobar() async* {
+  yield 1; // LINE_A.
+  yield 2; // LINE_B.
+}
+
+helper() async {
+  print('helper'); // LINE_C.
+  // ignore: unused_local_variable
+  await for (var i in foobar()) /* LINE_H */ {
+    debugger();
+    print('loop'); // LINE_D.
+  }
+  return null; // LINE_I.
+}
+
+testMain() {
+  debugger();
+  print('mmmmm'); // LINE_E.
+  helper(); // LINE_F.
+  print('z'); // LINE_G.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_E),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_F),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOut, // step out of generator.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_H), // await for.
+  stepInto,
+  hasStoppedAtBreakpoint, // debugger().
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D), // print.
+  stepInto,
+  hasStoppedAtBreakpoint, // await for.
+  stepInto,
+  hasStoppedAtBreakpoint, // back in generator.
+  stoppedAtLine(LINE_B),
+  stepOut, // step out of generator.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_H), // await for.
+  stepInto,
+  hasStoppedAtBreakpoint, // debugger().
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D), // print.
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_H), // await for.
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stepOut, // step out of generator.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_I), // return null.
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_step_out_test.dart b/pkg/vm_service/test/async_step_out_test.dart
new file mode 100644
index 0000000..4b80194
--- /dev/null
+++ b/pkg/vm_service/test/async_step_out_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 17;
+const LINE_B = 18;
+const LINE_C = 19;
+const LINE_D = 24;
+const LINE_E = 25;
+const LINE_F = 26;
+
+helper() async {
+  await null; // LINE_A.
+  print('helper'); // LINE_B.
+  print('foobar'); // LINE_C.
+}
+
+testMain() async {
+  debugger();
+  print('mmmmm'); // LINE_D.
+  await helper(); // LINE_E.
+  print('z'); // LINE_F.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_E),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  asyncNext,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  stepOver, // print.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  stepOut, // out of helper to awaiter testMain.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_F),
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
new file mode 100644
index 0000000..b6f32cb
--- /dev/null
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library service_test_common;
+
+import 'dart:async';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+typedef IsolateTest = Future<void> Function(
+    VmService service, IsolateRef isolate);
+typedef VMTest = Future<void> Function(VmService service);
+
+Future<void> smartNext(VmService service, IsolateRef isolateRef) async {
+  print('smartNext');
+  final isolate = await service.getIsolate(isolateRef.id);
+  if ((isolate.pauseEvent != null) &&
+      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+    Event event = isolate.pauseEvent;
+    // TODO(bkonyi): remove needless refetching of isolate object.
+    if (event?.atAsyncSuspension ?? false) {
+      return asyncNext(service, isolateRef);
+    } else {
+      return syncNext(service, isolateRef);
+    }
+  } else {
+    throw 'The program is already running';
+  }
+}
+
+Future<void> asyncNext(VmService service, IsolateRef isolateRef) async {
+  print('asyncNext');
+  final isolate = await service.getIsolate(isolateRef.id);
+  if ((isolate.pauseEvent != null) &&
+      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+    dynamic event = isolate.pauseEvent;
+    if (!event.atAsyncSuspension) {
+      throw 'No async continuation at this location';
+    } else {
+      return service.resume(isolateRef.id, step: 'OverAsyncSuspension');
+    }
+  } else {
+    throw 'The program is already running';
+  }
+}
+
+Future<void> syncNext(VmService service, IsolateRef isolateRef) async {
+  print('syncNext');
+  final isolate = await service.getIsolate(isolateRef.id);
+  if ((isolate.pauseEvent != null) &&
+      (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+    return service.resume(isolate.id, step: 'Over');
+  } else {
+    throw 'The program is already running';
+  }
+}
+
+Future<void> hasPausedFor(
+    VmService service, IsolateRef isolateRef, String kind) async {
+  var completer = Completer();
+  var subscription;
+  subscription = service.onDebugEvent.listen((event) async {
+    if ((isolateRef.id == event.isolate.id) && (event.kind == kind)) {
+      if (completer != null) {
+        try {
+          await service.streamCancel(EventStreams.kDebug);
+        } catch (_) {/* swallow exception */} finally {
+          subscription.cancel();
+          completer?.complete();
+          completer = null;
+        }
+      }
+    }
+  });
+  await service.streamListen(EventStreams.kDebug);
+
+  // Pause may have happened before we subscribed.
+  final isolate = await service.getIsolate(isolateRef.id);
+  if ((isolate.pauseEvent != null) && (isolate.pauseEvent.kind == kind)) {
+    if (completer != null) {
+      try {
+        await service.streamCancel(EventStreams.kDebug);
+      } catch (_) {/* swallow exception */} finally {
+        subscription.cancel();
+        completer?.complete();
+      }
+    }
+  }
+  return completer?.future; // Will complete when breakpoint hit.
+}
+
+Future<void> hasStoppedAtBreakpoint(VmService service, IsolateRef isolate) {
+  return hasPausedFor(service, isolate, EventKind.kPauseBreakpoint);
+}
+
+Future<void> hasStoppedPostRequest(VmService service, IsolateRef isolate) {
+  return hasPausedFor(service, isolate, EventKind.kPausePostRequest);
+}
+
+Future<void> hasStoppedWithUnhandledException(
+    VmService service, IsolateRef isolate) {
+  return hasPausedFor(service, isolate, EventKind.kPauseException);
+}
+
+Future<void> hasStoppedAtExit(VmService service, IsolateRef isolate) {
+  return hasPausedFor(service, isolate, EventKind.kPauseExit);
+}
+
+Future<void> hasPausedAtStart(VmService service, IsolateRef isolate) {
+  return hasPausedFor(service, isolate, EventKind.kPauseStart);
+}
+
+// Currying is your friend.
+IsolateTest setBreakpointAtLine(int line) {
+  return (VmService service, IsolateRef isolateRef) async {
+    print("Setting breakpoint for line $line");
+    final isolate = await service.getIsolate(isolateRef.id);
+    final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+    final script = lib.scripts.first;
+
+    Breakpoint bpt = await service.addBreakpoint(isolate.id, script.id, line);
+    print("Breakpoint is $bpt");
+  };
+}
+
+int _tokenToLine(Script script, int tokenPos) {
+  final table = script.tokenPosTable;
+  for (List line in table) {
+    // Each entry begins with a line number...
+    int lineNumber = line[0];
+    for (var pos = 1; pos < line.length; pos += 2) {
+      // ...and is followed by (token offset, col number) pairs.
+      int tokenOffset = line[pos];
+      if (tokenOffset == tokenPos) {
+        return lineNumber;
+      }
+    }
+  }
+  throw ArgumentError('Invalid tokenPos: $tokenPos');
+}
+
+IsolateTest stoppedAtLine(int line) {
+  return (VmService service, IsolateRef isolateRef) async {
+    print("Checking we are at line $line");
+
+    // Make sure that the isolate has stopped.
+    final isolate = await service.getIsolate(isolateRef.id);
+    expect(isolate.pauseEvent != EventKind.kResume, isTrue);
+
+    final stack = await service.getStack(isolateRef.id);
+
+    final frames = stack.frames;
+    expect(frames.length, greaterThanOrEqualTo(1));
+
+    final top = frames[0];
+    final script = await service.getObject(isolate.id, top.location.script.id);
+    int actualLine = _tokenToLine(script, top.location.tokenPos);
+    if (actualLine != line) {
+      print("Actual: $actualLine Line: $line");
+      final sb = StringBuffer();
+      sb.write("Expected to be at line $line but actually at line $actualLine");
+      sb.write("\nFull stack trace:\n");
+      for (Frame f in stack.frames) {
+        sb.write(" $f [${_tokenToLine(script, f.location.tokenPos)}]\n");
+      }
+      throw sb.toString();
+    } else {
+      print('Program is stopped at line: $line');
+    }
+  };
+}
+
+Future<void> resumeIsolate(VmService service, IsolateRef isolate) async {
+  Completer completer = Completer();
+  var subscription;
+  subscription = service.onDebugEvent.listen((event) async {
+    if (event.kind == EventKind.kResume) {
+      try {
+        await service.streamCancel(EventStreams.kDebug);
+      } catch (_) {/* swallow exception */} finally {
+        subscription.cancel();
+        completer.complete();
+      }
+    }
+  });
+  await service.streamListen(EventStreams.kDebug);
+  await service.resume(isolate.id);
+  return completer.future;
+}
+
+Future<void> stepOver(VmService service, IsolateRef isolateRef) async {
+  await service.resume(isolateRef.id, step: 'Over');
+  return hasStoppedAtBreakpoint(service, isolateRef);
+}
+
+Future<void> stepInto(VmService service, IsolateRef isolateRef) async {
+  await service.resume(isolateRef.id, step: 'Into');
+  return hasStoppedAtBreakpoint(service, isolateRef);
+}
+
+Future<void> stepOut(VmService service, IsolateRef isolateRef) async {
+  await service.resume(isolateRef.id, step: 'Out');
+  return hasStoppedAtBreakpoint(service, isolateRef);
+}
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
new file mode 100644
index 0000000..f57f3ee
--- /dev/null
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -0,0 +1,449 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test_helper;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'package:vm_service/vm_service_io.dart';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'service_test_common.dart';
+export 'service_test_common.dart' show IsolateTest, VMTest;
+
+/// Will be set to the http address of the VM's service protocol before
+/// any tests are invoked.
+String serviceHttpAddress;
+String serviceWebsocketAddress;
+
+const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
+const Map<String, String> _TESTEE_SPAWN_ENV = {_TESTEE_ENV_KEY: 'true'};
+bool _isTestee() {
+  return Platform.environment.containsKey(_TESTEE_ENV_KEY);
+}
+
+Uri _getTestUri() {
+  if (Platform.script.scheme == 'data') {
+    // If we're using pub to run these tests this value isn't a file URI.
+    // We'll need to parse the actual URI out...
+    final fileRegExp = RegExp(r'file:\/\/\/.*\.dart');
+    final path = fileRegExp.stringMatch(Platform.script.data.contentAsString());
+    if (path == null) {
+      throw 'Unable to determine file path for script!';
+    }
+    return Uri.parse(path);
+  } else {
+    return Platform.script;
+  }
+}
+
+class _ServiceTesteeRunner {
+  Future run(
+      {Function() testeeBefore,
+      Function() testeeConcurrent,
+      bool pause_on_start = false,
+      bool pause_on_exit = false}) async {
+    if (!pause_on_start) {
+      if (testeeBefore != null) {
+        var result = testeeBefore();
+        if (result is Future) {
+          await result;
+        }
+      }
+      print(''); // Print blank line to signal that testeeBefore has run.
+    }
+    if (testeeConcurrent != null) {
+      var result = testeeConcurrent();
+      if (result is Future) {
+        await result;
+      }
+    }
+    if (!pause_on_exit) {
+      // Wait around for the process to be killed.
+      // ignore: unawaited_futures
+      stdin.first.then((_) => exit(0));
+    }
+  }
+
+  void runSync(
+      {void Function() testeeBeforeSync,
+      void Function() testeeConcurrentSync,
+      bool pause_on_start = false,
+      bool pause_on_exit = false}) {
+    if (!pause_on_start) {
+      if (testeeBeforeSync != null) {
+        testeeBeforeSync();
+      }
+      print(''); // Print blank line to signal that testeeBefore has run.
+    }
+    if (testeeConcurrentSync != null) {
+      testeeConcurrentSync();
+    }
+    if (!pause_on_exit) {
+      // Wait around for the process to be killed.
+      stdin.first.then((_) => exit(0));
+    }
+  }
+}
+
+class _ServiceTesteeLauncher {
+  Process process;
+  List<String> args;
+  bool killedByTester = false;
+
+  _ServiceTesteeLauncher() : args = [_getTestUri().toFilePath()];
+
+  // Spawn the testee process.
+  Future<Process> _spawnProcess(
+    bool pause_on_start,
+    bool pause_on_exit,
+    bool pause_on_unhandled_exceptions,
+    bool testeeControlsServer,
+    bool useAuthToken,
+    List<String> extraArgs,
+  ) {
+    assert(pause_on_start != null);
+    assert(pause_on_exit != null);
+    assert(pause_on_unhandled_exceptions != null);
+    assert(testeeControlsServer != null);
+    assert(useAuthToken != null);
+    return _spawnDartProcess(
+        pause_on_start,
+        pause_on_exit,
+        pause_on_unhandled_exceptions,
+        testeeControlsServer,
+        useAuthToken,
+        extraArgs);
+  }
+
+  Future<Process> _spawnDartProcess(
+      bool pause_on_start,
+      bool pause_on_exit,
+      bool pause_on_unhandled_exceptions,
+      bool testeeControlsServer,
+      bool useAuthToken,
+      List<String> extraArgs) {
+    String dartExecutable = Platform.executable;
+
+    var fullArgs = <String>[];
+    if (pause_on_start) {
+      fullArgs.add('--pause-isolates-on-start');
+    }
+    if (pause_on_exit) {
+      fullArgs.add('--pause-isolates-on-exit');
+    }
+    if (!useAuthToken) {
+      fullArgs.add('--disable-service-auth-codes');
+    }
+    if (pause_on_unhandled_exceptions) {
+      fullArgs.add('--pause-isolates-on-unhandled-exceptions');
+    }
+    fullArgs.add('--profiler');
+    if (extraArgs != null) {
+      fullArgs.addAll(extraArgs);
+    }
+
+    fullArgs.addAll(Platform.executableArguments);
+    if (!testeeControlsServer) {
+      fullArgs.add('--enable-vm-service:0');
+    }
+    fullArgs.addAll(args);
+
+    return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
+  }
+
+  Future<Process> _spawnCommon(String executable, List<String> arguments,
+      Map<String, String> dartEnvironment) {
+    var environment = _TESTEE_SPAWN_ENV;
+    var bashEnvironment = StringBuffer();
+    environment.forEach((k, v) => bashEnvironment.write("$k=$v "));
+    if (dartEnvironment != null) {
+      dartEnvironment.forEach((k, v) {
+        arguments.insert(0, '-D$k=$v');
+      });
+    }
+    print('** Launching $bashEnvironment$executable ${arguments.join(' ')}');
+    return Process.start(executable, arguments, environment: environment);
+  }
+
+  Future<Uri> launch(
+      bool pause_on_start,
+      bool pause_on_exit,
+      bool pause_on_unhandled_exceptions,
+      bool testeeControlsServer,
+      bool useAuthToken,
+      List<String> extraArgs) {
+    return _spawnProcess(
+            pause_on_start,
+            pause_on_exit,
+            pause_on_unhandled_exceptions,
+            testeeControlsServer,
+            useAuthToken,
+            extraArgs)
+        .then((p) {
+      Completer<Uri> completer = Completer<Uri>();
+      process = p;
+      Uri uri;
+      var blank;
+      var first = true;
+      process.stdout
+          .transform(utf8.decoder)
+          .transform(LineSplitter())
+          .listen((line) {
+        const kObservatoryListening = 'Observatory listening on ';
+        if (line.startsWith(kObservatoryListening)) {
+          uri = Uri.parse(line.substring(kObservatoryListening.length));
+        }
+        if (pause_on_start || line == '') {
+          // Received blank line.
+          blank = true;
+        }
+        if ((uri != null) && (blank == true) && (first == true)) {
+          completer.complete(uri);
+          // Stop repeat completions.
+          first = false;
+          print('** Signaled to run test queries on $uri');
+        }
+        print('>testee>out> $line');
+      });
+      process.stderr
+          .transform(utf8.decoder)
+          .transform(LineSplitter())
+          .listen((line) {
+        print('>testee>err> $line');
+      });
+      process.exitCode.then((exitCode) {
+        if ((exitCode != 0) && !killedByTester) {
+          throw "Testee exited with $exitCode";
+        }
+        print("** Process exited");
+      });
+      return completer.future;
+    });
+  }
+
+  void requestExit() {
+    if (process != null) {
+      print('** Killing script');
+      if (process.kill()) {
+        killedByTester = true;
+      }
+    }
+  }
+}
+
+void setupAddresses(Uri serverAddress) {
+  serviceWebsocketAddress =
+      'ws://${serverAddress.authority}${serverAddress.path}ws';
+  serviceHttpAddress = 'http://${serverAddress.authority}${serverAddress.path}';
+}
+
+class _ServiceTesterRunner {
+  Future run(
+      {List<String> mainArgs,
+      List<String> extraArgs,
+      List<VMTest> vmTests,
+      List<IsolateTest> isolateTests,
+      bool pause_on_start = false,
+      bool pause_on_exit = false,
+      bool verbose_vm = false,
+      bool pause_on_unhandled_exceptions = false,
+      bool testeeControlsServer = false,
+      bool useAuthToken = false}) async {
+    var process = _ServiceTesteeLauncher();
+    VmService vm;
+    IsolateRef isolate;
+    setUpAll(() async {
+      await process
+          .launch(pause_on_start, pause_on_exit, pause_on_unhandled_exceptions,
+              testeeControlsServer, useAuthToken, extraArgs)
+          .then((Uri serverAddress) async {
+        if (mainArgs.contains("--gdb")) {
+          var pid = process.process.pid;
+          var wait = Duration(seconds: 10);
+          print("Testee has pid $pid, waiting $wait before continuing");
+          sleep(wait);
+        }
+        setupAddresses(serverAddress);
+        vm = await vmServiceConnectUri(serviceWebsocketAddress);
+        print('Done loading VM');
+        isolate = await getFirstIsolate(vm);
+      });
+    });
+
+    final name = _getTestUri().pathSegments.last;
+
+    test(name, () async {
+      // Run vm tests.
+      if (vmTests != null) {
+        var testIndex = 1;
+        var totalTests = vmTests.length;
+        for (var t in vmTests) {
+          print('$name [$testIndex/$totalTests]');
+          await t(vm);
+          testIndex++;
+        }
+      }
+
+      // Run isolate tests.
+      if (isolateTests != null) {
+        var testIndex = 1;
+        var totalTests = isolateTests.length;
+        for (var t in isolateTests) {
+          print('$name [$testIndex/$totalTests]');
+          await t(vm, isolate);
+          testIndex++;
+        }
+      }
+    });
+
+    tearDownAll(() {
+      print('All service tests completed successfully.');
+      process.requestExit();
+    });
+  }
+
+  Future<IsolateRef> getFirstIsolate(VmService service) async {
+    var vm = await service.getVM();
+
+    if (vm.isolates.isNotEmpty) {
+      return vm.isolates.first;
+    }
+    var completer = Completer();
+    StreamSubscription subscription;
+    subscription = service.onIsolateEvent.listen((Event event) async {
+      if (completer == null) {
+        await subscription.cancel();
+        return;
+      }
+      if (event.kind == EventKind.kIsolateRunnable) {
+        vm = await service.getVM();
+        assert(vm.isolates.isNotEmpty);
+        await subscription.cancel();
+        completer.complete(vm.isolates.first);
+        completer = null;
+      }
+    });
+
+    // The isolate may have started before we subscribed.
+    vm = await service.getVM();
+    if (vm.isolates.isNotEmpty) {
+      await subscription.cancel();
+      completer.complete(vm.isolates.first);
+      completer = null;
+    }
+    return await completer.future;
+  }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+Future<void> runIsolateTests(
+  List<String> mainArgs,
+  List<IsolateTest> tests, {
+  testeeBefore(),
+  testeeConcurrent(),
+  bool pause_on_start = false,
+  bool pause_on_exit = false,
+  bool verbose_vm = false,
+  bool pause_on_unhandled_exceptions = false,
+  bool testeeControlsServer = false,
+  bool useAuthToken = false,
+  List<String> extraArgs,
+}) async {
+  assert(!pause_on_start || testeeBefore == null);
+  if (_isTestee()) {
+    await _ServiceTesteeRunner().run(
+        testeeBefore: testeeBefore,
+        testeeConcurrent: testeeConcurrent,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit);
+  } else {
+    await _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        extraArgs: extraArgs,
+        isolateTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions,
+        testeeControlsServer: testeeControlsServer,
+        useAuthToken: useAuthToken);
+  }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+///
+/// This is a special version of this test harness specifically for the
+/// pause_on_unhandled_exceptions_test, which cannot properly function
+/// in an async context (because exceptions are *always* handled in async
+/// functions).
+void runIsolateTestsSynchronous(
+  List<String> mainArgs,
+  List<IsolateTest> tests, {
+  void testeeBefore(),
+  void testeeConcurrent(),
+  bool pause_on_start = false,
+  bool pause_on_exit = false,
+  bool verbose_vm = false,
+  bool pause_on_unhandled_exceptions = false,
+  List<String> extraArgs,
+}) {
+  assert(!pause_on_start || testeeBefore == null);
+  if (_isTestee()) {
+    _ServiceTesteeRunner().runSync(
+        testeeBeforeSync: testeeBefore,
+        testeeConcurrentSync: testeeConcurrent,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit);
+  } else {
+    _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        extraArgs: extraArgs,
+        isolateTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+  }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+Future<void> runVMTests(
+  List<String> mainArgs,
+  List<VMTest> tests, {
+  testeeBefore(),
+  testeeConcurrent(),
+  bool pause_on_start = false,
+  bool pause_on_exit = false,
+  bool verbose_vm = false,
+  bool pause_on_unhandled_exceptions = false,
+  List<String> extraArgs,
+}) async {
+  if (_isTestee()) {
+    await _ServiceTesteeRunner().run(
+        testeeBefore: testeeBefore,
+        testeeConcurrent: testeeConcurrent,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit);
+  } else {
+    await _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        extraArgs: extraArgs,
+        vmTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+  }
+}
diff --git a/pkg/vm_service/test/coverage_leaf_function_test.dart b/pkg/vm_service/test/coverage_leaf_function_test.dart
new file mode 100644
index 0000000..fe28924
--- /dev/null
+++ b/pkg/vm_service/test/coverage_leaf_function_test.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+String leafFunction() {
+  return "some constant";
+}
+
+void testFunction() {
+  debugger();
+  leafFunction();
+  debugger();
+}
+
+bool allRangesCompiled(coverage) {
+  for (int i = 0; i < coverage['ranges'].length; i++) {
+    if (!coverage['ranges'][i]['compiled']) {
+      return false;
+    }
+  }
+  return true;
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolate = await service.getIsolate(isolateRef.id);
+    final stack = await service.getStack(isolate.id);
+
+    // Make sure we are in the right place.
+    expect(stack.frames.length, greaterThanOrEqualTo(1));
+    expect(stack.frames[0].function.name, 'testFunction');
+
+    final root = await service.getObject(isolate.id, isolate.rootLib.id);
+    var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+    func = await service.getObject(isolate.id, func.id);
+
+    final expectedRange = {
+      'scriptIndex': 0,
+      'startPos': 397,
+      'endPos': 447,
+      'compiled': true,
+      'coverage': {
+        'hits': [],
+        'misses': [397]
+      }
+    };
+
+    final report = await service.getSourceReport(
+        isolate.id, [SourceReportKind.kCoverage],
+        scriptId: func.location.script.id,
+        tokenPos: func.location.tokenPos,
+        endTokenPos: func.location.endTokenPos,
+        forceCompile: true);
+    expect(report.ranges.length, 1);
+    expect(report.ranges[0].toJson(), expectedRange);
+    expect(report.scripts.length, 1);
+    expect(report.scripts[0].uri, endsWith('coverage_leaf_function_test.dart'));
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolate = await service.getIsolate(isolateRef.id);
+    final stack = await service.getStack(isolate.id);
+
+    // Make sure we are in the right place.
+    expect(stack.frames.length, greaterThanOrEqualTo(1));
+    expect(stack.frames[0].function.name, 'testFunction');
+
+    final root = await service.getObject(isolate.id, isolate.rootLib.id);
+    var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+    func = await service.getObject(isolate.id, func.id);
+
+    var expectedRange = {
+      'scriptIndex': 0,
+      'startPos': 397,
+      'endPos': 447,
+      'compiled': true,
+      'coverage': {
+        'hits': [397],
+        'misses': []
+      }
+    };
+
+    final report = await service.getSourceReport(
+        isolate.id, [SourceReportKind.kCoverage],
+        scriptId: func.location.script.id,
+        tokenPos: func.location.tokenPos,
+        endTokenPos: func.location.endTokenPos,
+        forceCompile: true);
+    expect(report.ranges.length, 1);
+    expect(report.ranges[0].toJson(), expectedRange);
+    expect(report.scripts.length, 1);
+    expect(report.scripts[0].uri, endsWith('coverage_leaf_function_test.dart'));
+  },
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testFunction);
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
new file mode 100644
index 0000000..ad4a106
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'common/test_helper.dart';
+
+int thing1;
+int thing2;
+
+testeeMain() {
+  thing1 = 3;
+  thing2 = 4;
+}
+
+Future evaluate(VmService service, isolate, target, x, y) async => await service
+    .evaluate(isolate.id, target.id, 'x + y', scope: {'x': x.id, 'y': y.id});
+
+final tests = <IsolateTest>[
+  (VmService service, IsolateRef isolateRef) async {
+    final isolate = await service.getIsolate(isolateRef.id);
+    final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+
+    final field1 = await service.getObject(
+        isolate.id, lib.variables.singleWhere((v) => v.name == 'thing1').id);
+    final thing1 = (await service.getObject(isolate.id, field1.staticValue.id));
+
+    final field2 = await service.getObject(
+        isolate.id, lib.variables.singleWhere((v) => v.name == 'thing2').id);
+    final thing2 = (await service.getObject(isolate.id, field2.staticValue.id));
+
+    var result = await evaluate(service, isolate, lib, thing1, thing2);
+    expect(result.valueAsString, equals('7'));
+
+    bool didThrow = false;
+    try {
+      result = await evaluate(service, isolate, lib, lib, lib);
+      print(result);
+    } catch (e) {
+      didThrow = true;
+      expect(e.toString(),
+          contains("Cannot evaluate against a VM-internal object"));
+    }
+    expect(didThrow, isTrue);
+
+    didThrow = false;
+    try {
+      result = await service.evaluate(isolate.id, lib.id, "x + y",
+          scope: <String, String>{"not&an&identifier": thing1.id});
+      print(result);
+    } catch (e) {
+      didThrow = true;
+      expect(e.toString(), contains("invalid 'scope' parameter"));
+    }
+    expect(didThrow, isTrue);
+  }
+];
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeBefore: testeeMain);
diff --git a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
new file mode 100644
index 0000000..70f640e
--- /dev/null
+++ b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+fib(n) {
+  if (n < 0) return 0;
+  if (n == 0) return 1;
+  return fib(n - 1) + fib(n - 2);
+}
+
+testeeDo() {
+  print("Testee doing something.");
+  fib(30);
+  print("Testee did something.");
+}
+
+Future checkSamples(VmService service, IsolateRef isolate) async {
+  // Grab all the samples.
+  final result = await service.getCpuSamples(isolate.id, 0, ~0);
+
+  final isString = TypeMatcher<String>();
+  final isInt = TypeMatcher<int>();
+  final isList = TypeMatcher<List>();
+  expect(result.functions.length, greaterThan(10),
+      reason: "Should have many functions");
+
+  final samples = result.samples;
+  expect(samples.length, greaterThan(10), reason: "Should have many samples");
+  expect(samples.length, result.sampleCount);
+
+  final sample = samples.first;
+  expect(sample.tid, isInt);
+  expect(sample.timestamp, isInt);
+  if (sample.vmTag != null) {
+    expect(sample.vmTag, isString);
+  }
+  if (sample.userTag != null) {
+    expect(sample.userTag, isString);
+  }
+  expect(sample.stack, isList);
+}
+
+var tests = <IsolateTest>[
+  (VmService service, IsolateRef i) => checkSamples(service, i),
+];
+
+var vmArgs = [
+  '--profiler=true',
+  '--profile-vm=false', // So this also works with DBC and KBC.
+];
+
+main(args) async =>
+    runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/pkg/vm_service/test/get_version_rpc_test.dart b/pkg/vm_service/test/get_version_rpc_test.dart
new file mode 100644
index 0000000..130bf21
--- /dev/null
+++ b/pkg/vm_service/test/get_version_rpc_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+
+var tests = <VMTest>[
+  (VmService vm) async {
+    final result = await vm.getVersion();
+    expect(result.major > 0, isTrue);
+    expect(result.minor >= 0, isTrue);
+  },
+];
+
+main([args = const <String>[]]) async => await runVMTests(args, tests);
diff --git a/pkg/vm_service/test/invoke_test.dart b/pkg/vm_service/test/invoke_test.dart
new file mode 100644
index 0000000..dcbb16e
--- /dev/null
+++ b/pkg/vm_service/test/invoke_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+libraryFunction() => "foobar1";
+
+class Klass {
+  static classFunction(x) => "foobar2" + x;
+  instanceFunction(x, y) => "foobar3" + x + y;
+}
+
+var instance;
+
+var apple;
+var banana;
+
+void testFunction() {
+  instance = Klass();
+  apple = "apple";
+  banana = "banana";
+  debugger();
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolate = await service.getIsolate(isolateRef.id);
+    final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+    final cls = lib.classes.singleWhere((cls) => cls.name == "Klass");
+    FieldRef fieldRef =
+        lib.variables.singleWhere((field) => field.name == "instance");
+    Field field = await service.getObject(isolate.id, fieldRef.id);
+    final instance = await service.getObject(isolate.id, field.staticValue.id);
+
+    fieldRef = lib.variables.singleWhere((field) => field.name == "apple");
+    field = await service.getObject(isolate.id, fieldRef.id);
+    final apple = await service.getObject(isolate.id, field.staticValue.id);
+    fieldRef = lib.variables.singleWhere((field) => field.name == "banana");
+    field = await service.getObject(isolate.id, fieldRef.id);
+    Instance banana = await service.getObject(isolate.id, field.staticValue.id);
+
+    dynamic result =
+        await service.invoke(isolate.id, lib.id, 'libraryFunction', []);
+    expect(result.valueAsString, equals('foobar1'));
+
+    result =
+        await service.invoke(isolate.id, cls.id, "classFunction", [apple.id]);
+    expect(result.valueAsString, equals('foobar2apple'));
+
+    result = await service.invoke(
+        isolate.id, instance.id, "instanceFunction", [apple.id, banana.id]);
+    expect(result.valueAsString, equals('foobar3applebanana'));
+
+    // Wrong arity.
+    await expectError(() => service
+        .invoke(isolate.id, instance.id, "instanceFunction", [apple.id]));
+    // No such target.
+    await expectError(() => service
+        .invoke(isolate.id, instance.id, "functionDoesNotExist", [apple.id]));
+  },
+  resumeIsolate,
+];
+
+expectError(func) async {
+  dynamic result = await func();
+  expect(result.type == 'Error' || result.type == '@Error', isTrue);
+}
+
+main([args = const <String>[]]) =>
+    runIsolateTests(args, tests, testeeConcurrent: testFunction);
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index be4a182..0a5f50f 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -94,9 +94,16 @@
   void dispose() {
     _streamSub.cancel();
     _completers.values.forEach((c) => c.completeError('disposed'));
-    if (_disposeHandler != null) _disposeHandler();
+    if (_disposeHandler != null) {
+      _disposeHandler();
+    }
+    if (!_onDoneCompleter.isCompleted) {
+      _onDoneCompleter.complete();
+    }
   }
 
+  Future get onDone => _onDoneCompleter.future;
+
   Future<T> _call<T>(String method, [Map args]) {
     String id = '${++_id}';
     Completer<T> completer = new Completer<T>();
@@ -736,6 +743,8 @@
 StreamController<String> _onSend = new StreamController.broadcast(sync: true);
 StreamController<String> _onReceive = new StreamController.broadcast(sync: true);
 
+final Completer _onDoneCompleter = new Completer();
+
 Map<String, StreamController<Event>> _eventControllers = {};
 
 StreamController<Event> _getEventController(String eventName) {
@@ -751,12 +760,18 @@
 
 VmService(Stream<dynamic> /*String|List<int>*/ inStream, void writeMessage(String message), {
   Log log,
-  DisposeHandler disposeHandler
+  DisposeHandler disposeHandler,
+  Future streamClosed,
 }) {
-  _streamSub = inStream.listen(_processMessage);
+  _streamSub = inStream.listen(_processMessage, onDone: ()=> _onDoneCompleter.complete());
   _writeMessage = writeMessage;
   _log = log == null ? new _NullLog() : log;
   _disposeHandler = disposeHandler;
+  streamClosed?.then((_) {
+    if (!_onDoneCompleter.isCompleted) {
+      _onDoneCompleter.complete();
+    }
+  });
 }
 
 @override
@@ -816,6 +831,11 @@
   return obj;
 }
 
+dynamic assertDynamic(dynamic obj) {
+  assertNotNull(obj);
+  return obj;
+}
+
 List<int> assertListOfInt(List<int> list) {
   for (int elem in list) {
     assertInt(elem);
@@ -910,6 +930,7 @@
             'ClassHeapStats',
             'CodeRegion',
             'ContextElement',
+            'CpuSample',
             'Flag',
             'Frame',
             'InboundReference',
diff --git a/runtime/.clang-tidy b/runtime/.clang-tidy
new file mode 100644
index 0000000..633aabf
--- /dev/null
+++ b/runtime/.clang-tidy
@@ -0,0 +1 @@
+Checks: -*,readability-implicit-bool-conversion
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 9211fc0..97fd635 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -798,7 +798,7 @@
 // objects. As these will be used by different threads the use of
 // these depends on the fact that the marking internally in the
 // Dart_CObject structure is not marking simple value objects.
-Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {0}};
+Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {false}};
 Dart_CObject CObject::api_true_ = {Dart_CObject_kBool, {true}};
 Dart_CObject CObject::api_false_ = {Dart_CObject_kBool, {false}};
 CObject CObject::null_(&api_null_);
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index c7a7266..3e5eaf9 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -233,7 +233,7 @@
     if (len > 2 && path[1] == ':') {
       *s++ = '/';
     }
-    for (const char *p = path; *p; ++p, ++s) {
+    for (const char* p = path; *p != '\0'; ++p, ++s) {
       *s = *p == '\\' ? '/' : *p;
     }
     *s = '\0';
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 37b4f28..6ed0744 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -403,15 +403,19 @@
     return true;
   }
   OverlappedBuffer* buffer = OverlappedBuffer::AllocateReadBuffer(kBufferSize);
+  // Set up pending_read_ before ReadDirectoryChangesW because it might be
+  // needed in ReadComplete invoked on event loop thread right away if data is
+  // also ready right away.
+  pending_read_ = buffer;
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   BOOL ok = ReadDirectoryChangesW(handle_, buffer->GetBufferStart(),
                                   buffer->GetBufferSize(), recursive_, events_,
                                   NULL, buffer->GetCleanOverlapped(), NULL);
   if (ok || (GetLastError() == ERROR_IO_PENDING)) {
     // Completing asynchronously.
-    pending_read_ = buffer;
     return true;
   }
+  pending_read_ = nullptr;
   OverlappedBuffer::DisposeBuffer(buffer);
   return false;
 }
@@ -1103,7 +1107,8 @@
         // If out events (can write events) have been requested, and there
         // are no pending writes, meaning any writes are already complete,
         // post an out event immediately.
-        if ((events & (1 << kOutEvent)) != 0) {
+        intptr_t out_event_mask = 1 << kOutEvent;
+        if ((events & out_event_mask) != 0) {
           if (!handle->HasPendingWrite()) {
             if (handle->is_client_socket()) {
               if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
@@ -1114,14 +1119,25 @@
                 }
               }
             } else {
-              intptr_t event_mask = 1 << kOutEvent;
-              if ((handle->Mask() & event_mask) != 0) {
-                Dart_Port port = handle->NextNotifyDartPort(event_mask);
-                DartUtils::PostInt32(port, event_mask);
+              if ((handle->Mask() & out_event_mask) != 0) {
+                Dart_Port port = handle->NextNotifyDartPort(out_event_mask);
+                DartUtils::PostInt32(port, out_event_mask);
               }
             }
           }
         }
+        // Similarly, if in events (can read events) have been requested, and
+        // there is pending data available, post an in event immediately.
+        intptr_t in_event_mask = 1 << kInEvent;
+        if ((events & in_event_mask) != 0) {
+          if (handle->data_ready_ != nullptr &&
+              !handle->data_ready_->IsEmpty()) {
+            if ((handle->Mask() & in_event_mask) != 0) {
+              Dart_Port port = handle->NextNotifyDartPort(in_event_mask);
+              DartUtils::PostInt32(port, in_event_mask);
+            }
+          }
+        }
       } else if (IS_COMMAND(msg->data, kShutdownReadCommand)) {
         ASSERT(handle->is_client_socket());
 
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 6e6223e..85145b1 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -39,6 +39,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // Tests for Dart -> native calls.
+//
+// Note: If this interface is changed please also update
+// sdk/runtime/tools/dartfuzz/ffiapi.dart
 
 // Sums two ints and adds 42.
 // Simple function to test trampolines.
@@ -309,7 +312,7 @@
 // Coordinate.
 // Used for testing function pointers with structs.
 DART_EXPORT Coord* CoordinateUnOpTrice(CoordUnOp unop, Coord* coord) {
-  std::cout << "CoordinateUnOpTrice(" << unop << ", " << coord << ")\n";
+  std::cout << "CoordinateUnOpTrice(" << &unop << ", " << coord << ")\n";
   Coord* retval = unop(unop(unop(coord)));
   std::cout << "returning " << retval << "\n";
   return retval;
@@ -324,7 +327,7 @@
 DART_EXPORT IntptrBinOp IntptrAdditionClosure() {
   std::cout << "IntptrAdditionClosure()\n";
   IntptrBinOp retval = [](intptr_t a, intptr_t b) { return a + b; };
-  std::cout << "returning " << retval << "\n";
+  std::cout << "returning " << &retval << "\n";
   return retval;
 }
 
@@ -343,7 +346,7 @@
 DART_EXPORT int64_t* NullableInt64ElemAt1(int64_t* a) {
   std::cout << "NullableInt64ElemAt1(" << a << ")\n";
   int64_t* retval;
-  if (a) {
+  if (a != nullptr) {
     std::cout << "not null pointer, address: " << a << "\n";
     retval = a + 1;
   } else {
@@ -436,7 +439,7 @@
   retval += vls->k;
   retval += vls->smallLastField;
   std::cout << retval << "\n";
-  if (vls->parent) {
+  if (vls->parent != nullptr) {
     std::cout << "has parent\n";
     retval += vls->parent->a;
   }
@@ -756,7 +759,7 @@
 }
 
 DART_EXPORT int TestThrowExceptionPointer(void* (*fn)()) {
-  CHECK_EQ(fn(), reinterpret_cast<void*>(42));
+  CHECK_EQ(fn(), nullptr);
   return 0;
 }
 
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 3acf44a..a72d807 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -1507,7 +1507,7 @@
 // Inspired by sdk/lib/core/uri.dart
 UriDecoder::UriDecoder(const char* uri) : uri_(uri) {
   const char* ch = uri;
-  while ((*ch != 0) && (*ch != '%')) {
+  while ((*ch != '\0') && (*ch != '%')) {
     ch++;
   }
   if (*ch == 0) {
@@ -1524,7 +1524,7 @@
   strncpy(dest, uri, i);
   decoded_ = dest;
   dest += i;
-  while (*ch) {
+  while (*ch != '\0') {
     if (*ch != '%') {
       *(dest++) = *(ch++);
       continue;
diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc
index c23c133..f16b87c 100644
--- a/runtime/bin/file_system_watcher_linux.cc
+++ b/runtime/bin/file_system_watcher_linux.cc
@@ -132,7 +132,7 @@
       } else {
         Dart_ListSetAt(event, 2, Dart_Null());
       }
-      Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+      Dart_ListSetAt(event, 3, Dart_NewBoolean((e->mask & IN_MOVED_TO) != 0u));
       Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
       Dart_ListSetAt(events, i, event);
       i++;
diff --git a/runtime/bin/file_system_watcher_win.cc b/runtime/bin/file_system_watcher_win.cc
index 990f905..33654c4 100644
--- a/runtime/bin/file_system_watcher_win.cc
+++ b/runtime/bin/file_system_watcher_win.cc
@@ -56,6 +56,10 @@
 
   DirectoryWatchHandle* handle =
       new DirectoryWatchHandle(dir, list_events, recursive);
+  // Issue a read directly, to be sure events are tracked from now on. This is
+  // okay, since in Dart, we create the socket and start reading immidiately.
+  handle->EnsureInitialized(EventHandler::delegate());
+  handle->IssueRead();
   return reinterpret_cast<intptr_t>(handle);
 }
 
diff --git a/runtime/bin/file_test.cc b/runtime/bin/file_test.cc
index 967eec8..60adf31 100644
--- a/runtime/bin/file_test.cc
+++ b/runtime/bin/file_test.cc
@@ -41,7 +41,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all characters 'c'
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == 'c') {
       *t++ = '%';
       *t++ = '6';
@@ -70,7 +70,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all characters 'c'
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == 'c') {
       *t++ = '%';
       *t++ = '6';
@@ -110,7 +110,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all characters 'c'
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == 'c') {
       *t++ = '%';
       *t++ = '6';
@@ -151,7 +151,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all spaces
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == ' ') {
       *t++ = '%';
       *t++ = '2';
@@ -180,7 +180,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all characters 'c'
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == 'c') {
       *t++ = '%';
       *t++ = 'f';
@@ -200,7 +200,7 @@
       strlen(kFilename) * 3 + 1));
   char* t = encoded;
   // percent-encode all characters 'c'
-  for (const char* p = kFilename; *p; p++) {
+  for (const char* p = kFilename; *p != '\0'; p++) {
     if (*p == 'c') {
       *t++ = '%';
       *t++ = 'f';
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 63f940cd3..d7a2a4e 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -864,11 +864,6 @@
   TimerUtils::InitOnce();
   EventHandler::Start();
 
-#if !defined(PRODUCT)
-  // Constant true in PRODUCT mode.
-  vm_options.AddArgument("--load_deferred_eagerly");
-#endif
-
   if (IsSnapshottingForPrecompilation()) {
     vm_options.AddArgument("--precompilation");
   } else if ((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT)) {
@@ -909,7 +904,7 @@
         MapFile(load_vm_snapshot_instructions_filename, File::kReadExecute,
                 &init_params.vm_snapshot_instructions);
   }
-  if (load_isolate_snapshot_data_filename) {
+  if (load_isolate_snapshot_data_filename != nullptr) {
     mapped_isolate_snapshot_data =
         MapFile(load_isolate_snapshot_data_filename, File::kReadOnly,
                 &isolate_snapshot_data);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 935f2ea..f34671c 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -129,12 +129,12 @@
   V(SecurityContext_TrustBuiltinRoots, 1)                                      \
   V(SecurityContext_UseCertificateChainBytes, 3)                               \
   V(ServerSocket_Accept, 2)                                                    \
-  V(ServerSocket_CreateBindListen, 6)                                          \
+  V(ServerSocket_CreateBindListen, 7)                                          \
   V(SocketBase_IsBindError, 2)                                                 \
   V(Socket_Available, 1)                                                       \
-  V(Socket_CreateBindConnect, 4)                                               \
+  V(Socket_CreateBindConnect, 5)                                               \
   V(Socket_CreateBindDatagram, 6)                                              \
-  V(Socket_CreateConnect, 3)                                                   \
+  V(Socket_CreateConnect, 4)                                                   \
   V(Socket_GetPort, 1)                                                         \
   V(Socket_GetRemotePeer, 1)                                                   \
   V(Socket_GetError, 1)                                                        \
diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc
index 772fbcc..f6a5bd6 100644
--- a/runtime/bin/loader.cc
+++ b/runtime/bin/loader.cc
@@ -619,7 +619,7 @@
     return result;
   }
   if (tag == Dart_kImportExtensionTag) {
-    if (strncmp(url_string, "dart-ext:", 9)) {
+    if (strncmp(url_string, "dart-ext:", 9) != 0) {
       return DartUtils::NewError(
           "Native extensions must use the dart-ext: scheme.");
     }
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 54d9306..f23de40 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -275,7 +275,7 @@
     }
   } else {
     result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
-    if (Dart_IsError(result)) return result;
+    if (Dart_IsError(result)) return result != nullptr;
 
     if (isolate_group_data->kernel_buffer().get() != nullptr) {
       // Various core-library parts will send requests to the Loader to resolve
@@ -284,7 +284,7 @@
       // bypasses normal source code loading paths that initialize it.
       const char* resolved_script_uri = NULL;
       result = Dart_StringToCString(result, &resolved_script_uri);
-      if (Dart_IsError(result)) return result;
+      if (Dart_IsError(result)) return result != nullptr;
       Loader::InitForSnapshot(resolved_script_uri, isolate_data);
     }
   }
@@ -661,12 +661,12 @@
     }
   }
 
-  if (flags->copy_parent_code && callback_data) {
-    IsolateGroupData* parent_isolate_data =
-        reinterpret_cast<IsolateGroupData*>(callback_data);
-    parent_kernel_buffer = parent_isolate_data->kernel_buffer();
+  if (flags->copy_parent_code && callback_data != nullptr) {
+    auto parent_isolate_group_data =
+        reinterpret_cast<IsolateData*>(callback_data)->isolate_group_data();
+    parent_kernel_buffer = parent_isolate_group_data->kernel_buffer();
     kernel_buffer = parent_kernel_buffer.get();
-    kernel_buffer_size = parent_isolate_data->kernel_buffer_size();
+    kernel_buffer_size = parent_isolate_group_data->kernel_buffer_size();
   }
 
   if (kernel_buffer == NULL && !isolate_run_app_snapshot) {
@@ -1139,13 +1139,6 @@
                              &app_isolate_snapshot_instructions);
   }
 
-#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  // Constant true if PRODUCT or DART_PRECOMPILED_RUNTIME.
-  if ((Options::gen_snapshot_kind() != kNone) || vm_run_app_snapshot) {
-    vm_options.AddArgument("--load_deferred_eagerly");
-  }
-#endif
-
   if (Options::gen_snapshot_kind() == kAppJIT) {
     vm_options.AddArgument("--fields_may_be_reset");
   }
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index b356da5..ee4516e 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -340,7 +340,7 @@
     return false;
   }
   int ver = 0;
-  for (int i = 0; value[i]; ++i) {
+  for (int i = 0; value[i] != '\0'; ++i) {
     if (value[i] >= '0' && value[i] <= '9') {
       ver = (ver * 10) + value[i] - '0';
     } else {
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index b4a5020..694577e 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -253,7 +253,7 @@
   CHECK_RESULT(result);
 
   // Setup kernel service as the main script for this isolate.
-  if (kernel_service_buffer) {
+  if (kernel_service_buffer != nullptr) {
     result = Dart_LoadScriptFromKernel(kernel_service_buffer,
                                        kernel_service_buffer_size);
     CHECK_RESULT(result);
diff --git a/runtime/bin/secure_socket_filter.cc b/runtime/bin/secure_socket_filter.cc
index c1d9f57..bcb9bee 100644
--- a/runtime/bin/secure_socket_filter.cc
+++ b/runtime/bin/secure_socket_filter.cc
@@ -677,7 +677,7 @@
     bytes_processed =
         BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length);
     if (bytes_processed <= 0) {
-      bool retry = BIO_should_retry(socket_side_);
+      bool retry = BIO_should_retry(socket_side_) != 0;
       if (!retry) {
         if (SSL_LOG_DATA)
           Syslog::Print("BIO_write failed in ReadEncryptedBuffer\n");
diff --git a/runtime/bin/secure_socket_utils.cc b/runtime/bin/secure_socket_utils.cc
index 362e891..259b06e 100644
--- a/runtime/bin/secure_socket_utils.cc
+++ b/runtime/bin/secure_socket_utils.cc
@@ -39,7 +39,7 @@
     }
     if ((path != NULL) && (line >= 0)) {
       const char* file = strrchr(path, sep[0]);
-      path = file ? file + 1 : path;
+      path = file != nullptr ? file + 1 : path;
       text_buffer->Printf("(%s:%d)", path, line);
     }
   }
diff --git a/runtime/bin/security_context.cc b/runtime/bin/security_context.cc
index 3300b11..983e5e2 100644
--- a/runtime/bin/security_context.cc
+++ b/runtime/bin/security_context.cc
@@ -76,7 +76,7 @@
     filter->callback_error = result;
     return 0;
   }
-  return DartUtils::GetBooleanValue(result);
+  return static_cast<int>(DartUtils::GetBooleanValue(result));
 }
 
 SSLCertContext* SSLCertContext::GetSecurityContext(Dart_NativeArguments args) {
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 0b590e6..33f6907 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -259,6 +259,12 @@
   Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
   int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
   SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
+  if (addr.addr.sa_family == AF_INET6) {
+    Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 3);
+    int64_t scope_id =
+        DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+    SocketAddress::SetAddrScope(&addr, scope_id);
+  }
   intptr_t socket = Socket::CreateConnect(addr);
   OSError error;
   if (socket >= 0) {
@@ -278,6 +284,12 @@
   SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
   RawAddr sourceAddr;
   SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr);
+  if (addr.addr.sa_family == AF_INET6) {
+    Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 4);
+    int64_t scope_id =
+        DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+    SocketAddress::SetAddrScope(&addr, scope_id);
+  }
   intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr);
   OSError error;
   if (socket >= 0) {
@@ -627,6 +639,12 @@
       Dart_GetNativeArgument(args, 3), 0, 65535);
   bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
   bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
+  if (addr.addr.sa_family == AF_INET6) {
+    Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 6);
+    int64_t scope_id =
+        DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+    SocketAddress::SetAddrScope(&addr, scope_id);
+  }
 
   Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
   Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen(
@@ -664,7 +682,7 @@
       array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
       for (intptr_t i = 0; i < addresses->count(); i++) {
         SocketAddress* addr = addresses->GetAt(i);
-        CObjectArray* entry = new CObjectArray(CObject::NewArray(3));
+        CObjectArray* entry = new CObjectArray(CObject::NewArray(4));
 
         CObjectInt32* type =
             new CObjectInt32(CObject::NewInt32(addr->GetType()));
@@ -678,6 +696,10 @@
         CObjectUint8Array* data = SocketAddress::ToCObject(raw);
         entry->SetAt(2, data);
 
+        CObjectInt64* scope_id = new CObjectInt64(
+            CObject::NewInt64(SocketAddress::GetAddrScope(raw)));
+        entry->SetAt(3, scope_id);
+
         array->SetAt(i + 1, entry);
       }
       result = array;
diff --git a/runtime/bin/socket_base.cc b/runtime/bin/socket_base.cc
index 060c710..8789c43 100644
--- a/runtime/bin/socket_base.cc
+++ b/runtime/bin/socket_base.cc
@@ -49,7 +49,8 @@
       return false;
     }
     return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr,
-                  sizeof(a.in6.sin6_addr)) == 0;
+                  sizeof(a.in6.sin6_addr)) == 0 &&
+           a.in6.sin6_scope_id == b.in6.sin6_scope_id;
   } else {
     UNREACHABLE();
     return false;
@@ -141,6 +142,18 @@
   memmove(data->Buffer(), in_addr, in_addr_len);
   return data;
 }
+void SocketAddress::SetAddrScope(RawAddr* addr, intptr_t scope_id) {
+  if (addr->addr.sa_family != AF_INET6) return;
+  addr->in6.sin6_scope_id = scope_id;
+}
+
+intptr_t SocketAddress::GetAddrScope(const RawAddr& addr) {
+  if (addr.addr.sa_family == AF_INET6) {
+    return addr.in6.sin6_scope_id;
+  } else {
+    return 0;
+  }
+}
 
 void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
   const char* address =
diff --git a/runtime/bin/socket_base.h b/runtime/bin/socket_base.h
index 8cab1aa..404357b 100644
--- a/runtime/bin/socket_base.h
+++ b/runtime/bin/socket_base.h
@@ -73,6 +73,8 @@
   static intptr_t GetAddrPort(const RawAddr& addr);
   static Dart_Handle ToTypedData(const RawAddr& addr);
   static CObjectUint8Array* ToCObject(const RawAddr& addr);
+  static void SetAddrScope(RawAddr* addr, intptr_t scope_id);
+  static intptr_t GetAddrScope(const RawAddr& addr);
 
  private:
   char as_string_[INET6_ADDRSTRLEN];
diff --git a/runtime/bin/socket_base_linux.cc b/runtime/bin/socket_base_linux.cc
index 87aedbd..9a52d96 100644
--- a/runtime/bin/socket_base_linux.cc
+++ b/runtime/bin/socket_base_linux.cc
@@ -46,7 +46,7 @@
                                       int len) {
   socklen_t salen = SocketAddress::GetAddrLength(addr);
   return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len, NULL,
-                                        0, NI_NUMERICHOST) == 0));
+                                        0, NI_NUMERICHOST) == 0)) != 0;
 }
 
 bool SocketBase::IsBindError(intptr_t error_number) {
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index d6149e6..c1336e3 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -137,6 +137,7 @@
   final String address;
   final String _host;
   final Uint8List _in_addr;
+  final int _scope_id;
 
   InternetAddressType get type => _in_addr.length == _IPv4AddrLength
       ? InternetAddressType.IPv4
@@ -185,7 +186,8 @@
 
   Future<InternetAddress> reverse() => _NativeSocket.reverseLookup(this);
 
-  _InternetAddress(this.address, this._host, this._in_addr);
+  _InternetAddress(this.address, this._host, this._in_addr,
+      [this._scope_id = 0]);
 
   factory _InternetAddress.parse(String address) {
     if (address is! String) {
@@ -387,7 +389,7 @@
       } else {
         return response.skip(1).map<InternetAddress>((result) {
           var type = new InternetAddressType._from(result[0]);
-          return new _InternetAddress(result[1], host, result[2]);
+          return new _InternetAddress(result[1], host, result[2], result[3]);
         }).toList();
       }
     });
@@ -430,8 +432,40 @@
     });
   }
 
+  static String escapeLinkLocalAddress(String host) {
+    // if the host contains escape, host is an IPv6 address with scope ID.
+    // Remove '25' before feeding into native calls.
+    int index = host.indexOf('%');
+    if (index >= 0) {
+      if (!checkLinkLocalAddress(host)) {
+        // The only well defined usage is link-local address. Checks Section 4 of https://tools.ietf.org/html/rfc6874.
+        // If it is not a valid link-local address and contains escape character, throw an exception.
+        throw new FormatException(
+            '${host} is not a valid link-local address but contains %. Scope id should be used as part of link-local address.',
+            host,
+            index);
+      }
+      if (host.startsWith("25", index + 1)) {
+        // Remove '25' after '%' if present
+        host = host.replaceRange(index + 1, index + 3, '');
+      }
+    }
+    return host;
+  }
+
+  static bool checkLinkLocalAddress(String host) {
+    // The shortest possible link-local address is [fe80::1]
+    if (host.length < 7) return false;
+    var char = host[2];
+    return host.startsWith('fe') &&
+        (char == '8' || char == '9' || char == 'a' || char == 'b');
+  }
+
   static Future<ConnectionTask<_NativeSocket>> startConnect(
       host, int port, sourceAddress) {
+    if (host is String) {
+      host = escapeLinkLocalAddress(host);
+    }
     _throwOnBadPort(port);
     if (sourceAddress != null && sourceAddress is! _InternetAddress) {
       if (sourceAddress is String) {
@@ -465,11 +499,12 @@
         socket.localAddress = address;
         var result;
         if (sourceAddress == null) {
-          result = socket.nativeCreateConnect(address._in_addr, port);
+          result = socket.nativeCreateConnect(
+              address._in_addr, port, address._scope_id);
         } else {
           assert(sourceAddress is _InternetAddress);
-          result = socket.nativeCreateBindConnect(
-              address._in_addr, port, sourceAddress._in_addr);
+          result = socket.nativeCreateBindConnect(address._in_addr, port,
+              sourceAddress._in_addr, address._scope_id);
         }
         if (result is OSError) {
           // Keep first error, if present.
@@ -594,13 +629,15 @@
   static Future<_NativeSocket> bind(
       host, int port, int backlog, bool v6Only, bool shared) async {
     _throwOnBadPort(port);
-
+    if (host is String) {
+      host = escapeLinkLocalAddress(host);
+    }
     final address = await _resolveHost(host);
 
     var socket = new _NativeSocket.listen();
     socket.localAddress = address;
     var result = socket.nativeCreateBindListen(
-        address._in_addr, port, backlog, v6Only, shared);
+        address._in_addr, port, backlog, v6Only, shared, address._scope_id);
     if (result is OSError) {
       throw new SocketException("Failed to create server socket",
           osError: result, address: address, port: port);
@@ -1183,12 +1220,13 @@
       native "Socket_WriteList";
   nativeSendTo(List<int> buffer, int offset, int bytes, Uint8List address,
       int port) native "Socket_SendTo";
-  nativeCreateConnect(Uint8List addr, int port) native "Socket_CreateConnect";
-  nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr)
-      native "Socket_CreateBindConnect";
+  nativeCreateConnect(Uint8List addr, int port, int scope_id)
+      native "Socket_CreateConnect";
+  nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr,
+      int scope_id) native "Socket_CreateBindConnect";
   bool isBindError(int errorNumber) native "SocketBase_IsBindError";
   nativeCreateBindListen(Uint8List addr, int port, int backlog, bool v6Only,
-      bool shared) native "ServerSocket_CreateBindListen";
+      bool shared, int scope_id) native "ServerSocket_CreateBindListen";
   nativeCreateBindDatagram(Uint8List addr, int port, bool reuseAddress,
       bool reusePort, int ttl) native "Socket_CreateBindDatagram";
   nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
diff --git a/runtime/bin/stdio_linux.cc b/runtime/bin/stdio_linux.cc
index 18e19e8..2ed9a90 100644
--- a/runtime/bin/stdio_linux.cc
+++ b/runtime/bin/stdio_linux.cc
@@ -86,7 +86,7 @@
 }
 
 bool Stdin::AnsiSupported(intptr_t fd, bool* supported) {
-  *supported = isatty(fd) && TermHasXTerm();
+  *supported = (isatty(fd) != 0) && TermHasXTerm();
   return true;
 }
 
@@ -102,7 +102,7 @@
 }
 
 bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
-  *supported = isatty(fd) && TermHasXTerm();
+  *supported = (isatty(fd) != 0) && TermHasXTerm();
   return true;
 }
 
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 7e60a43..3d060be 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3456,7 +3456,6 @@
  *  current VM. The instructions piece must be loaded with read and execute
  *  permissions; the data piece may be loaded as read-only.
  *
- *   - Requires the VM to have been started with --load-deferred-eagerly.
  *   - Requires the VM to have not been started with --precompilation.
  *   - Not supported when targeting IA32 or DBC.
  *   - The VM writing the snapshot and the VM reading the snapshot must be the
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index f1eab3a..bac0ef1 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -24,7 +24,7 @@
 #if !defined(PRODUCT)
   GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
   Debugger* debugger = isolate->debugger();
-  if (!debugger) {
+  if (debugger == nullptr) {
     return when.raw();
   }
   if (when.value()) {
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 347cd05..f103f2e 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -429,88 +429,6 @@
   return Integer::New(SizeOf(type_arg));
 }
 
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER) &&        \
-    !defined(TARGET_ARCH_DBC)
-// Generates assembly to trampoline from native code into Dart.
-static uword CompileNativeCallback(const Function& c_signature,
-                                   const Function& dart_target,
-                                   const Instance& exceptional_return) {
-  Thread* const thread = Thread::Current();
-
-  uword entry_point = 0;
-  const int32_t callback_id = thread->AllocateFfiCallbackId(&entry_point);
-  ASSERT(NativeCallbackTrampolines::Enabled() == (entry_point != 0));
-
-  // Create a new Function named 'FfiCallback' and stick it in the 'dart:ffi'
-  // library. Note that these functions will never be invoked by Dart, so it
-  // doesn't matter that they all have the same name.
-  Zone* const Z = thread->zone();
-  const String& name = String::Handle(Symbols::New(thread, "FfiCallback"));
-  const Library& lib = Library::Handle(Z, Library::FfiLibrary());
-  const Class& owner_class = Class::Handle(Z, lib.toplevel_class());
-  const Function& function =
-      Function::Handle(Z, Function::New(name, RawFunction::kFfiTrampoline,
-                                        /*is_static=*/true,
-                                        /*is_const=*/false,
-                                        /*is_abstract=*/false,
-                                        /*is_external=*/false,
-                                        /*is_native=*/false, owner_class,
-                                        TokenPosition::kMinSource));
-  function.set_is_debuggable(false);
-
-  // Set callback-specific fields which the flow-graph builder needs to generate
-  // the body.
-  function.SetFfiCSignature(c_signature);
-  function.SetFfiCallbackId(callback_id);
-  function.SetFfiCallbackTarget(dart_target);
-
-  // We require that the exceptional return value for functions returning 'Void'
-  // must be 'null', since native code should not look at the result.
-  if (compiler::ffi::NativeTypeIsVoid(
-          AbstractType::Handle(c_signature.result_type())) &&
-      !exceptional_return.IsNull()) {
-    Exceptions::ThrowUnsupportedError(
-        "Only 'null' may be used as the exceptional return value for a "
-        "callback returning void.");
-  }
-
-  // We need to load the exceptional return value as a constant in the generated
-  // function. This means we need to ensure that it's in old space and has no
-  // (transitively) mutable fields. This is done by checking (asserting) that
-  // it's a built-in FFI class, whose fields are all immutable, or a
-  // user-defined Pointer class, which has no fields.
-  //
-  // TODO(36730): We'll need to extend this when we support passing/returning
-  // structs by value.
-  ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber() ||
-         exceptional_return.IsPointer());
-  if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
-    function.SetFfiCallbackExceptionalReturn(
-        Instance::Handle(exceptional_return.CopyShallowToOldSpace(thread)));
-  } else {
-    function.SetFfiCallbackExceptionalReturn(exceptional_return);
-  }
-
-  // We compile the callback immediately because we need to return a pointer to
-  // the entry-point. Native calls do not use patching like Dart calls, so we
-  // cannot compile it lazily.
-  const Object& result =
-      Object::Handle(Z, Compiler::CompileOptimizedFunction(thread, function));
-  if (result.IsError()) {
-    Exceptions::PropagateError(Error::Cast(result));
-  }
-  ASSERT(result.IsCode());
-  const Code& code = Code::Cast(result);
-
-  thread->SetFfiCallbackCode(callback_id, code);
-
-  if (entry_point != 0) {
-    return entry_point;
-  } else {
-    return code.EntryPoint();
-  }
-}
-#endif
 
 // Static invocations to this method are translated directly in streaming FGB
 // and bytecode FGB. However, we can still reach this entrypoint in the bytecode
@@ -545,80 +463,6 @@
 #endif
 }
 
-DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 2) {
-#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) ||          \
-    defined(TARGET_ARCH_DBC)
-  // https://github.com/dart-lang/sdk/issues/37295
-  // FFI is supported, but callbacks are not.
-  Exceptions::ThrowUnsupportedError(
-      "FFI callbacks are not yet supported in AOT or on DBC.");
-#else
-  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return,
-                               arguments->NativeArgAt(1));
-
-  if (!type_arg.IsInstantiated() || !type_arg.IsFunctionType()) {
-    // TODO(35902): Remove this when dynamic invocations of fromFunction are
-    // prohibited.
-    Exceptions::ThrowUnsupportedError(
-        "Type argument to fromFunction must an instantiated function type.");
-  }
-
-  const Function& native_signature =
-      Function::Handle(Type::Cast(type_arg).signature());
-  Function& func = Function::Handle(closure.function());
-  TypeArguments& type_args = TypeArguments::Handle(zone);
-  type_args = TypeArguments::New(1);
-  type_args.SetTypeAt(Pointer::kNativeTypeArgPos, type_arg);
-  type_args = type_args.Canonicalize();
-
-  Class& native_function_class =
-      Class::Handle(isolate->class_table()->At(kFfiNativeFunctionCid));
-  const auto& error =
-      Error::Handle(native_function_class.EnsureIsFinalized(Thread::Current()));
-  if (!error.IsNull()) {
-    Exceptions::PropagateError(error);
-  }
-
-  Type& native_function_type = Type::Handle(
-      Type::New(native_function_class, type_args, TokenPosition::kNoSource));
-  native_function_type ^=
-      ClassFinalizer::FinalizeType(Class::Handle(), native_function_type);
-  native_function_type ^= native_function_type.Canonicalize();
-
-  // The FE verifies that the target of a 'fromFunction' is a static method, so
-  // the value we see here must be a static tearoff. See ffi_use_sites.dart for
-  // details.
-  //
-  // TODO(36748): Define hot-reload semantics of native callbacks. We may need
-  // to look up the target by name.
-  ASSERT(func.IsImplicitClosureFunction());
-  func = func.parent_function();
-  ASSERT(func.is_static());
-
-  const AbstractType& return_type =
-      AbstractType::Handle(native_signature.result_type());
-  if (compiler::ffi::NativeTypeIsVoid(return_type)) {
-    if (!exceptional_return.IsNull()) {
-      const String& error = String::Handle(
-          String::NewFormatted("Exceptional return argument to 'fromFunction' "
-                               "must be null for functions returning void."));
-      Exceptions::ThrowArgumentError(error);
-    }
-  } else if (!compiler::ffi::NativeTypeIsPointer(return_type) &&
-             exceptional_return.IsNull()) {
-    const String& error = String::Handle(String::NewFormatted(
-        "Exceptional return argument to 'fromFunction' must not be null."));
-    Exceptions::ThrowArgumentError(error);
-  }
-
-  return Pointer::New(
-      native_function_type,
-      CompileNativeCallback(native_signature, func, exceptional_return));
-#endif
-}
-
 DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1));
@@ -692,8 +536,8 @@
 
   const auto& typed_data_class =
       Class::Handle(zone, isolate->class_table()->At(cid));
-  const auto& error = Error::Handle(
-      zone, typed_data_class.EnsureIsFinalized(Thread::Current()));
+  const auto& error =
+      Error::Handle(zone, typed_data_class.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
   }
@@ -703,6 +547,91 @@
       Heap::kNew);
 }
 
+DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) {
+#if defined(TARGET_ARCH_DBC)
+  Exceptions::ThrowUnsupportedError(
+      "FFI callbacks are not yet supported on DBC.");
+#elif defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+  // Calls to this function are removed by the flow-graph builder in AOT.
+  // See StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction().
+  UNREACHABLE();
+#else
+  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return,
+                               arguments->NativeArgAt(1));
+
+  ASSERT(type_arg.IsInstantiated() && type_arg.IsFunctionType());
+  const Function& native_signature =
+      Function::Handle(zone, Type::Cast(type_arg).signature());
+  Function& func = Function::Handle(zone, closure.function());
+
+  // The FE verifies that the target of a 'fromFunction' is a static method, so
+  // the value we see here must be a static tearoff. See ffi_use_sites.dart for
+  // details.
+  //
+  // TODO(36748): Define hot-reload semantics of native callbacks. We may need
+  // to look up the target by name.
+  ASSERT(func.IsImplicitClosureFunction());
+  func = func.parent_function();
+  ASSERT(func.is_static());
+
+  // We are returning an object which is not an Instance here. This is only OK
+  // because we know that the result will be passed directly to
+  // _pointerFromFunction and will not leak out into user code.
+  arguments->SetReturn(
+      Function::Handle(zone, compiler::ffi::NativeCallbackFunction(
+                                 native_signature, func, exceptional_return)));
+
+  // Because we have already set the return value.
+  return Object::sentinel().raw();
+#endif
+}
+
+DEFINE_NATIVE_ENTRY(Ffi_pointerFromFunction, 1, 1) {
+  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
+  const Function& function =
+      Function::CheckedHandle(zone, arguments->NativeArg0());
+
+  Code& code = Code::Handle(zone);
+
+#if defined(DART_PRECOMPILED_RUNTIME)
+  code = function.CurrentCode();
+
+  // Blobs snapshots don't support BSS-relative relocations required by native
+  // callbacks (yet). Issue an error if the code has an unpatched relocation.
+  if (!code.VerifyBSSRelocations()) {
+    Exceptions::ThrowUnsupportedError(
+        "FFI callbacks are not yet supported in blobs snapshots. Please use "
+        "ELF or Assembly snapshots instead.");
+  }
+#else
+  // We compile the callback immediately because we need to return a pointer to
+  // the entry-point. Native calls do not use patching like Dart calls, so we
+  // cannot compile it lazily.
+  const Object& result = Object::Handle(
+      zone, Compiler::CompileOptimizedFunction(thread, function));
+  if (result.IsError()) {
+    Exceptions::PropagateError(Error::Cast(result));
+  }
+  ASSERT(result.IsCode());
+  code ^= result.raw();
+#endif
+
+  ASSERT(!code.IsNull());
+  thread->SetFfiCallbackCode(function.FfiCallbackId(), code);
+
+  uword entry_point = code.EntryPoint();
+#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
+  if (NativeCallbackTrampolines::Enabled()) {
+    entry_point = isolate->native_callback_trampolines()->TrampolineForId(
+        function.FfiCallbackId());
+  }
+#endif
+
+  return Pointer::New(type_arg, entry_point);
+}
+
 #if defined(TARGET_ARCH_DBC)
 
 void FfiMarshalledArguments::SetFunctionAddress(uint64_t value) const {
diff --git a/runtime/lib/ffi_native_type_patch.dart b/runtime/lib/ffi_native_type_patch.dart
index edc43950..cd229de2 100644
--- a/runtime/lib/ffi_native_type_patch.dart
+++ b/runtime/lib/ffi_native_type_patch.dart
@@ -68,8 +68,8 @@
 
 @patch
 @pragma("vm:entry-point")
-class Void extends NativeType {}
+abstract class Void extends NativeType {}
 
 @patch
 @pragma("vm:entry-point")
-class NativeFunction<T extends Function> extends NativeType {}
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/runtime/lib/ffi_patch.dart b/runtime/lib/ffi_patch.dart
index c16cd72..089f0c9 100644
--- a/runtime/lib/ffi_patch.dart
+++ b/runtime/lib/ffi_patch.dart
@@ -23,6 +23,25 @@
 dynamic _asExternalTypedData(Pointer ptr, int count)
     native "Ffi_asExternalTypedData";
 
+// Returns a Function object for a native callback.
+//
+// Calls to [Pointer.fromFunction] are re-written by the FE into calls to this
+// method + _pointerFromFunction. All three arguments must be constants.
+//
+// In AOT we evaluate calls to this function during precompilation and replace
+// them with Constant instruction referencing the callback trampoline, to ensure
+// that it will be precompiled.
+//
+// In all JIT modes we call a native runtime entry. We *cannot* use the IL
+// implementation, since that would pull the callback trampoline into JIT
+// snapshots. The callback trampolines can only be serialized into AOT snapshots
+// because they embed the addresses of runtime routines in JIT mode.
+Object _nativeCallbackFunction<NS extends Function>(Function target,
+    Object exceptionalReturn) native "Ffi_nativeCallbackFunction";
+
+Pointer<NS> _pointerFromFunction<NS extends NativeFunction>(Object function)
+    native "Ffi_pointerFromFunction";
+
 @patch
 @pragma("vm:entry-point")
 class Pointer<T extends NativeType> {
@@ -32,10 +51,18 @@
   @patch
   factory Pointer.fromAddress(int ptr) => _fromAddress(ptr);
 
+  // All static calls to this method are replaced by the FE into
+  // _nativeCallbackFunction + _pointerFromFunction.
+  //
+  // We still need to throw an error on a dynamic invocations, invocations
+  // through tearoffs or reflective calls.
   @patch
   static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
       @DartRepresentationOf("T") Function f,
-      Object exceptionalReturn) native "Ffi_fromFunction";
+      [Object exceptionalReturn]) {
+    throw UnsupportedError(
+        "Pointer.fromFunction cannot be called dynamically.");
+  }
 
   // TODO(sjindel): When NNBD is available, we should change `value` to be
   // non-null.
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f8a102c..058f2ec 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -128,7 +128,7 @@
   }
 
   ~SpawnIsolateTask() override {
-    if (parent_isolate_) {
+    if (parent_isolate_ != nullptr) {
       parent_isolate_->DecrementSpawnCount();
     }
   }
diff --git a/runtime/lib/lib_prefix.dart b/runtime/lib/lib_prefix.dart
index fe12660..f588ee3 100644
--- a/runtime/lib/lib_prefix.dart
+++ b/runtime/lib/lib_prefix.dart
@@ -11,74 +11,7 @@
     throw "Unreachable";
   }
 
-  bool _load() native "LibraryPrefix_load";
-  Object _loadError() native "LibraryPrefix_loadError";
-  bool isLoaded() native "LibraryPrefix_isLoaded";
-  bool _invalidateDependentCode()
-      native "LibraryPrefix_invalidateDependentCode";
+  bool isLoaded() => true;
 
-  loadLibrary() {
-    for (int i = 0; i < _outstandingLoadRequests.length; i++) {
-      if (_outstandingLoadRequests[i][0] == this) {
-        return _outstandingLoadRequests[i][1].future;
-      }
-    }
-
-    var completer = new Completer<bool>();
-    var pair = new List();
-    pair.add(this);
-    pair.add(completer);
-    _outstandingLoadRequests.add(pair);
-    Timer.run(() {
-      var hasCompleted = this._load();
-      // Loading can complete immediately, for example when the same
-      // library has been loaded eagerly or through another deferred
-      // prefix. If that is the case, we must invalidate the dependent
-      // code and complete the future now since there will be no callback
-      // from the VM.
-      if (hasCompleted && !completer.isCompleted) {
-        _invalidateDependentCode();
-        completer.complete(true);
-        _outstandingLoadRequests.remove(pair);
-      }
-    });
-    return completer.future;
-  }
-}
-
-// A list of two element lists. The first element is the _LibraryPrefix. The
-// second element is the Completer for the load request.
-var _outstandingLoadRequests = new List<List>();
-
-// Called from the VM when an outstanding load request has finished.
-@pragma("vm:entry-point", "call")
-_completeDeferredLoads() {
-  // Determine which outstanding load requests have completed and complete
-  // their completer (with an error or true). For outstanding load requests
-  // which have not completed, remember them for next time in
-  // stillOutstandingLoadRequests.
-  var stillOutstandingLoadRequests = new List<List>();
-
-  // Make a copy of the outstandingRequests because the call to _load below
-  // may recursively trigger another call to |_completeDeferredLoads|, which
-  // can cause |_outstandingLoadRequests| to be modified.
-  var outstandingRequests = _outstandingLoadRequests.toList();
-  for (int i = 0; i < outstandingRequests.length; i++) {
-    var prefix = outstandingRequests[i][0];
-    var completer = outstandingRequests[i][1];
-    var error = prefix._loadError();
-    if (completer.isCompleted) {
-      // Already completed. Skip.
-      continue;
-    }
-    if (error != null) {
-      completer.completeError(error);
-    } else if (prefix._load()) {
-      prefix._invalidateDependentCode();
-      completer.complete(true);
-    } else {
-      stillOutstandingLoadRequests.add(outstandingRequests[i]);
-    }
-  }
-  _outstandingLoadRequests = stillOutstandingLoadRequests;
+  loadLibrary() => new Future.value(true);
 }
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3d291af..a76d721 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -253,20 +253,27 @@
   args.SetAt(4, Bool::Get(func.is_static()));
 
   intptr_t kind_flags = 0;
-  kind_flags |= (func.is_abstract() << Mirrors::kAbstract);
-  kind_flags |= (func.IsGetterFunction() << Mirrors::kGetter);
-  kind_flags |= (func.IsSetterFunction() << Mirrors::kSetter);
+  kind_flags |=
+      (static_cast<intptr_t>(func.is_abstract()) << Mirrors::kAbstract);
+  kind_flags |=
+      (static_cast<intptr_t>(func.IsGetterFunction()) << Mirrors::kGetter);
+  kind_flags |=
+      (static_cast<intptr_t>(func.IsSetterFunction()) << Mirrors::kSetter);
   bool is_ctor = (func.kind() == RawFunction::kConstructor);
-  kind_flags |= (is_ctor << Mirrors::kConstructor);
-  kind_flags |= ((is_ctor && func.is_const()) << Mirrors::kConstCtor);
+  kind_flags |= (static_cast<intptr_t>(is_ctor) << Mirrors::kConstructor);
+  kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_const())
+                 << Mirrors::kConstCtor);
   kind_flags |=
-      ((is_ctor && func.IsGenerativeConstructor()) << Mirrors::kGenerativeCtor);
+      (static_cast<intptr_t>(is_ctor && func.IsGenerativeConstructor())
+       << Mirrors::kGenerativeCtor);
+  kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_redirecting())
+                 << Mirrors::kRedirectingCtor);
+  kind_flags |= (static_cast<intptr_t>(is_ctor && func.IsFactory())
+                 << Mirrors::kFactoryCtor);
   kind_flags |=
-      ((is_ctor && func.is_redirecting()) << Mirrors::kRedirectingCtor);
-  kind_flags |= ((is_ctor && func.IsFactory()) << Mirrors::kFactoryCtor);
-  kind_flags |= (func.is_external() << Mirrors::kExternal);
+      (static_cast<intptr_t>(func.is_external()) << Mirrors::kExternal);
   bool is_synthetic = func.is_no_such_method_forwarder();
-  kind_flags |= (is_synthetic << Mirrors::kSynthetic);
+  kind_flags |= (static_cast<intptr_t>(is_synthetic) << Mirrors::kSynthetic);
   args.SetAt(5, Smi::Handle(Smi::New(kind_flags)));
 
   return CreateMirror(Symbols::_LocalMethodMirror(), args);
@@ -366,11 +373,14 @@
 
 static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
                                                   const Instance& importer,
-                                                  const Namespace& ns,
+                                                  const Library& importee,
+                                                  const Array& show_names,
+                                                  const Array& hide_names,
+                                                  const Object& metadata,
                                                   const LibraryPrefix& prefix,
+                                                  const String& prefix_name,
                                                   const bool is_import,
                                                   const bool is_deferred) {
-  const Library& importee = Library::Handle(ns.library());
   const Instance& importee_mirror =
       Instance::Handle(CreateLibraryMirror(thread, importee));
   if (importee_mirror.IsNull()) {
@@ -378,8 +388,6 @@
     return Instance::null();
   }
 
-  const Array& show_names = Array::Handle(ns.show_names());
-  const Array& hide_names = Array::Handle(ns.hide_names());
   intptr_t n = show_names.IsNull() ? 0 : show_names.Length();
   intptr_t m = hide_names.IsNull() ? 0 : hide_names.Length();
   const Array& combinators = Array::Handle(Array::New(n + m));
@@ -396,12 +404,6 @@
     combinators.SetAt(i++, t);
   }
 
-  Object& metadata = Object::Handle(ns.GetMetadata());
-  if (metadata.IsError()) {
-    Exceptions::PropagateError(Error::Cast(metadata));
-    UNREACHABLE();
-  }
-
   const Array& args = Array::Handle(Array::New(7));
   args.SetAt(0, importer);
   if (importee.Loaded() || prefix.IsNull()) {
@@ -413,14 +415,109 @@
     args.SetAt(1, prefix);
   }
   args.SetAt(2, combinators);
-  args.SetAt(3, prefix.IsNull() ? Object::null_object()
-                                : String::Handle(prefix.name()));
+  args.SetAt(3, prefix_name);
   args.SetAt(4, Bool::Get(is_import));
   args.SetAt(5, Bool::Get(is_deferred));
   args.SetAt(6, metadata);
   return CreateMirror(Symbols::_LocalLibraryDependencyMirror(), args);
 }
 
+static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
+                                                  const Instance& importer,
+                                                  const Namespace& ns,
+                                                  const LibraryPrefix& prefix,
+                                                  const bool is_import,
+                                                  const bool is_deferred) {
+  const Library& importee = Library::Handle(ns.library());
+  const Array& show_names = Array::Handle(ns.show_names());
+  const Array& hide_names = Array::Handle(ns.hide_names());
+
+  Object& metadata = Object::Handle(ns.GetMetadata());
+  if (metadata.IsError()) {
+    Exceptions::PropagateError(Error::Cast(metadata));
+    UNREACHABLE();
+  }
+
+  auto& prefix_name = String::Handle();
+  if (!prefix.IsNull()) {
+    prefix_name = prefix.name();
+  }
+
+  return CreateLibraryDependencyMirror(thread, importer, importee, show_names,
+                                       hide_names, metadata, prefix,
+                                       prefix_name, is_import, is_deferred);
+}
+
+static RawGrowableObjectArray* CreateBytecodeLibraryDependencies(
+    Thread* thread,
+    const Library& lib,
+    const Instance& lib_mirror) {
+  ASSERT(lib.is_declared_in_bytecode());
+
+  // Make sure top level class (containing annotations) is fully loaded.
+  lib.EnsureTopLevelClassIsFinalized();
+
+  const auto& deps = GrowableObjectArray::Handle(GrowableObjectArray::New());
+  Array& metadata = Array::Handle(lib.GetExtendedMetadata(lib, 1));
+  if (metadata.Length() == 0) {
+    return deps.raw();
+  }
+
+  // Library has the only element in the extended metadata.
+  metadata ^= metadata.At(0);
+  if (metadata.IsNull()) {
+    return deps.raw();
+  }
+
+  auto& desc = Array::Handle();
+  auto& target_uri = String::Handle();
+  auto& importee = Library::Handle();
+  auto& is_export = Bool::Handle();
+  auto& is_deferred = Bool::Handle();
+  auto& prefix_name = String::Handle();
+  auto& show_names = Array::Handle();
+  auto& hide_names = Array::Handle();
+  auto& dep_metadata = Instance::Handle();
+  auto& dep = Instance::Handle();
+  const auto& no_prefix = LibraryPrefix::Handle();
+
+  for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
+    desc ^= metadata.At(i);
+    // Each dependency is represented as an array with the following layout:
+    //  [0] = target library URI (String)
+    //  [1] = is_export (bool)
+    //  [2] = is_deferred (bool)
+    //  [3] = prefix (String or null)
+    //  [4] = list of show names (List<String>)
+    //  [5] = list of hide names (List<String>)
+    //  [6] = annotations
+    // The library dependencies are encoded by getLibraryAnnotations(),
+    // pkg/vm/lib/bytecode/gen_bytecode.dart.
+    target_uri ^= desc.At(0);
+    is_export ^= desc.At(1);
+    is_deferred ^= desc.At(2);
+    prefix_name ^= desc.At(3);
+    show_names ^= desc.At(4);
+    hide_names ^= desc.At(5);
+    dep_metadata ^= desc.At(6);
+
+    importee = Library::LookupLibrary(thread, target_uri);
+    if (importee.IsNull()) {
+      continue;
+    }
+    ASSERT(importee.Loaded());
+
+    dep = CreateLibraryDependencyMirror(
+        thread, lib_mirror, importee, show_names, hide_names, dep_metadata,
+        no_prefix, prefix_name, !is_export.value(), is_deferred.value());
+    if (!dep.IsNull()) {
+      deps.Add(dep);
+    }
+  }
+
+  return deps.raw();
+}
+
 DEFINE_NATIVE_ENTRY(LibraryMirror_fromPrefix, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(LibraryPrefix, prefix,
                                arguments->NativeArgAt(0));
@@ -436,6 +533,10 @@
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
   const Library& lib = Library::Handle(ref.GetLibraryReferent());
 
+  if (lib.is_declared_in_bytecode()) {
+    return CreateBytecodeLibraryDependencies(thread, lib, lib_mirror);
+  }
+
   Array& ports = Array::Handle();
   Namespace& ns = Namespace::Handle();
   Instance& dep = Instance::Handle();
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 2c5f526..7d40155 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -184,37 +184,6 @@
   return Smi::New(hash_val);
 }
 
-DEFINE_NATIVE_ENTRY(LibraryPrefix_invalidateDependentCode, 0, 1) {
-  const LibraryPrefix& prefix =
-      LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  prefix.InvalidateDependentCode();
-  return Bool::Get(true).raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 0, 1) {
-  const LibraryPrefix& prefix =
-      LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  bool hasCompleted = prefix.LoadLibrary();
-  return Bool::Get(hasCompleted).raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_loadError, 0, 1) {
-  const LibraryPrefix& prefix =
-      LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  // Currently all errors are Dart instances, e.g. I/O errors
-  // created by deferred loading code. LanguageErrors from
-  // failed loading or finalization attempts are propagated and result
-  // in the isolate's death.
-  const Instance& error = Instance::Handle(zone, prefix.LoadError());
-  return error.raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
-  const LibraryPrefix& prefix =
-      LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  return Bool::Get(prefix.is_loaded()).raw();
-}
-
 DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
 #if defined(ARCH_IS_64_BIT)
   return Bool::True().raw();
diff --git a/runtime/lib/wasm.cc b/runtime/lib/wasm.cc
new file mode 100644
index 0000000..7d0c06f
--- /dev/null
+++ b/runtime/lib/wasm.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/unicode.h"
+#include "vm/bootstrap_natives.h"
+#include "vm/dart_entry.h"
+
+namespace dart {
+
+int callWasm(const char* name, int n) {
+  return 100 * n;
+}
+
+// This is a temporary API for prototyping.
+DEFINE_NATIVE_ENTRY(Wasm_callFunction, 0, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(String, fn_name, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg, arguments->NativeArgAt(1));
+
+  intptr_t len = Utf8::Length(fn_name);
+  std::unique_ptr<char> name = std::unique_ptr<char>(new char[len + 1]);
+  fn_name.ToUTF8(reinterpret_cast<uint8_t*>(name.get()), len);
+  name.get()[len] = 0;
+
+  return Smi::New(callWasm(name.get(), arg.AsInt64Value()));
+}
+
+}  // namespace dart
diff --git a/runtime/lib/wasm_patch.dart b/runtime/lib/wasm_patch.dart
new file mode 100644
index 0000000..2af1b20
--- /dev/null
+++ b/runtime/lib/wasm_patch.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:_internal" show patch;
+
+@patch
+int _callWasm(String name, int arg) native "Wasm_callFunction";
diff --git a/runtime/lib/wasm_sources.gni b/runtime/lib/wasm_sources.gni
new file mode 100644
index 0000000..6067612
--- /dev/null
+++ b/runtime/lib/wasm_sources.gni
@@ -0,0 +1,7 @@
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+wasm_runtime_cc_files = [ "wasm.cc" ]
+
+wasm_runtime_dart_files = [ "wasm_patch.dart" ]
diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn
index 1399468..22fb0fb 100644
--- a/runtime/observatory/BUILD.gn
+++ b/runtime/observatory/BUILD.gn
@@ -40,7 +40,9 @@
     rebase_path(output),
     "--packages=" + rebase_path(".packages"),
   ]
-  if (!is_debug) {
+  if (is_debug) {
+    args += [ "--enable-asserts" ]
+  } else {
     args += [ "--minify" ]
   }
 }
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index f4bd617..a2fa1dd 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -12,19 +12,12 @@
 import 'package:logging/logging.dart';
 
 class _ReadStream {
-  final List<ByteData> _chunks;
-  int _chunkIndex = 0;
-  int _byteIndex = 0;
+  final Uint8List _buffer;
+  int _position = 0;
 
-  _ReadStream(this._chunks);
+  _ReadStream(this._buffer);
 
-  int readByte() {
-    while (_byteIndex >= _chunks[_chunkIndex].lengthInBytes) {
-      _chunkIndex++;
-      _byteIndex = 0;
-    }
-    return _chunks[_chunkIndex].getUint8(_byteIndex++);
-  }
+  int readByte() => _buffer[_position++];
 
   /// Read one ULEB128 number.
   int readUnsigned() {
@@ -342,15 +335,48 @@
   }
 }
 
+class _InstancesIterable extends IterableBase<SnapshotObject> {
+  final _SnapshotGraph _graph;
+  final int _cid;
+
+  _InstancesIterable(this._graph, this._cid);
+
+  Iterator<SnapshotObject> get iterator => new _InstancesIterator(_graph, _cid);
+}
+
+class _InstancesIterator implements Iterator<SnapshotObject> {
+  final _SnapshotGraph _graph;
+  final int _cid;
+
+  int _nextId = 0;
+  SnapshotObject current;
+
+  _InstancesIterator(this._graph, this._cid);
+
+  bool moveNext() {
+    while (_nextId < _graph._N) {
+      if (_graph._cids[_nextId] == _cid) {
+        current = new _SnapshotObject._(_nextId++, _graph, "");
+        return true;
+      }
+      _nextId++;
+    }
+    return false;
+  }
+}
+
 abstract class SnapshotClass {
   String get name;
   int get externalSize;
   int get shallowSize;
   int get ownedSize;
   int get instanceCount;
+  Iterable<SnapshotObject> get instances;
 }
 
 class _SnapshotClass implements SnapshotClass {
+  final _SnapshotGraph _graph;
+  final int _cid;
   final String name;
   final String libName;
   final String libUri;
@@ -370,7 +396,10 @@
   int get externalSize => liveExternalSize;
   int get instanceCount => liveInstanceCount;
 
-  _SnapshotClass(this.name, this.libName, this.libUri);
+  Iterable<SnapshotObject> get instances =>
+      new _InstancesIterable(_graph, _cid);
+
+  _SnapshotClass(this._graph, this._cid, this.name, this.libName, this.libUri);
 }
 
 abstract class SnapshotGraph {
@@ -384,7 +413,7 @@
   Iterable<SnapshotClass> get classes;
   Iterable<SnapshotObject> get objects;
 
-  factory SnapshotGraph(List<ByteData> chunks) => new _SnapshotGraph(chunks);
+  factory SnapshotGraph(Uint8List encoded) => new _SnapshotGraph(encoded);
   Stream<String> process();
 }
 
@@ -403,7 +432,7 @@
 const kUnknownFieldName = "<unknown>";
 
 class _SnapshotGraph implements SnapshotGraph {
-  _SnapshotGraph(List<ByteData> chunks) : this._chunks = chunks;
+  _SnapshotGraph(Uint8List encoded) : this._encoded = encoded;
 
   int get size => _liveShallowSize + _liveExternalSize;
   int get shallowSize => _liveShallowSize;
@@ -466,8 +495,8 @@
     (() async {
       // We build futures here instead of marking the steps as async to avoid the
       // heavy lifting being inside a transformed method.
-      var stream = new _ReadStream(_chunks);
-      _chunks = null;
+      var stream = new _ReadStream(_encoded);
+      _encoded = null;
 
       controller.add("Loading classes...");
       await new Future(() => _readClasses(stream));
@@ -520,7 +549,7 @@
     return controller.stream;
   }
 
-  List<ByteData> _chunks;
+  Uint8List _encoded;
 
   int _kStackCid;
   int _kFieldCid;
@@ -572,7 +601,7 @@
 
     var K = stream.readUnsigned();
     var classes = new List<_SnapshotClass>(K + 1);
-    classes[0] = new _SnapshotClass("Root", "", "");
+    classes[0] = new _SnapshotClass(this, 0, "Root", "", "");
 
     for (var cid = 1; cid <= K; cid++) {
       int flags = stream.readUnsigned();
@@ -580,7 +609,7 @@
       String libName = stream.readUtf8();
       String libUri = stream.readUtf8();
       String reserved = stream.readUtf8();
-      var cls = new _SnapshotClass(name, libName, libUri);
+      final cls = new _SnapshotClass(this, cid, name, libName, libUri);
       int edgeCount = stream.readUnsigned();
       for (int i = 0; i < edgeCount; i++) {
         int flags = stream.readUnsigned();
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index 51ea321..70cb593 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -13,7 +13,7 @@
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/service.dart' as S;
 import 'package:observatory/service_common.dart' as SC;
-import 'package:observatory/service_html.dart' as SH;
+import 'package:observatory/src/repositories/timeline_base.dart';
 
 part 'src/repositories/allocation_profile.dart';
 part 'src/repositories/breakpoint.dart';
diff --git a/runtime/observatory/lib/sample_profile.dart b/runtime/observatory/lib/sample_profile.dart
index e755ad3..914906d 100644
--- a/runtime/observatory/lib/sample_profile.dart
+++ b/runtime/observatory/lib/sample_profile.dart
@@ -5,7 +5,6 @@
 library sample_profiler;
 
 import 'dart:async';
-import 'dart:typed_data';
 import 'package:logging/logging.dart';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/service.dart';
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index 4e47b95..66ff984 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -205,7 +205,7 @@
       var dataLength = bytes.lengthInBytes - dataOffset;
       var metadata = _utf8Decoder.convert(new Uint8List.view(
           bytes.buffer, bytes.offsetInBytes + metadataOffset, metadataLength));
-      var data = new ByteData.view(
+      var data = new Uint8List.view(
           bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
       var map = _parseJSON(metadata);
       if (map == null || map['method'] != 'streamNotify') {
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index bcc224a..d55dc86 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -179,6 +179,7 @@
       ];
     }).catchError((e, stack) {
       Logger.root.severe('VMPage visit error: $e');
+      Logger.root.severe('Stack: $stack');
       // Reroute to vm-connect.
       app.locationManager.go(Uris.vmConnect());
     });
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
index f921c44..1446716 100644
--- a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
+++ b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
@@ -199,7 +199,7 @@
       int i = top - tail_length;
       for (final HtmlElement e in _buffer.children) {
         if (0 <= i && i < _items.length) {
-          e..style.display = null;
+          e.style.display = null;
           _update(e, _items[i], i);
         } else {
           e.style.display = 'hidden';
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 320a7603..f6fafd0 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -116,7 +116,7 @@
             selectedTag: _tag, queue: _r.queue)
           ..onTagChange.listen((e) {
             _tag = e.element.selectedTag;
-            _request(forceFetch: true);
+            _request();
           }))
         .element);
     if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
index 77de515..a01d842 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
@@ -90,7 +90,6 @@
     var create;
     var update;
     var search;
-
     switch (type) {
       case M.SampleProfileType.cpu:
         create = _createCpuRow;
diff --git a/runtime/observatory/lib/src/elements/cpu_profile_table.dart b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
index cd07545..e225e48 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile_table.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
@@ -120,7 +120,7 @@
         (new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh))
             .element,
         (new NavRefreshElement(label: 'Clear', queue: _r.queue)
-              ..onRefresh.listen(_clearCpuProfile))
+              ..onRefresh.listen(_clearCpuSamples))
             .element,
         new NavNotifyElement(_notifications, queue: _r.queue).element
       ]),
@@ -152,7 +152,10 @@
             createHeader: _createFunctionHeader,
             search: _searchFunction,
             queue: _r.queue);
-    _functions.items = _progress.profile.functions.toList()
+    // If there's no samples, don't populate the function list.
+    _functions.items = (_progress.profile.sampleCount != 0)
+        ? _progress.profile.functions.toList()
+        : []
       ..sort(_createSorter(_Table.functions));
     _functions.takeIntoView(_selected);
     _callers = _callers ??
@@ -428,7 +431,7 @@
     }
   }
 
-  Future _clearCpuProfile(RefreshEvent e) async {
+  Future _clearCpuSamples(RefreshEvent e) async {
     e.element.disabled = true;
     await _request(clear: true);
     e.element.disabled = false;
@@ -461,12 +464,12 @@
     }
     switch (_sortingDirection[table]) {
       case _SortingDirection.ascending:
-        int sort(M.ProfileFunction a, M.ProfileFunction b) {
+        int sort(a, b) {
           return getter(a).compareTo(getter(b));
         }
         return sort;
       case _SortingDirection.descending:
-        int sort(M.ProfileFunction a, M.ProfileFunction b) {
+        int sort(a, b) {
           return getter(b).compareTo(getter(a));
         }
         return sort;
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index ee4664f..8460715 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -27,6 +27,7 @@
 import 'package:observatory/src/elements/nav/refresh.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/tree_map.dart';
 import 'package:observatory/utils.dart';
 
 enum HeapSnapshotTreeMode {
@@ -35,9 +36,108 @@
   mergedDominatorTree,
   mergedDominatorTreeMap,
   ownershipTable,
+  ownershipTreeMap,
+  classesTable,
+  classesTreeMap,
   successors,
   predecessors,
-  classes,
+}
+
+class DominatorTreeMap extends TreeMap<SnapshotObject> {
+  HeapSnapshotElement element;
+  DominatorTreeMap(this.element);
+
+  int getSize(SnapshotObject node) => node.retainedSize;
+  String getType(SnapshotObject node) => node.klass.name;
+  String getLabel(SnapshotObject node) => node.description;
+  SnapshotObject getParent(SnapshotObject node) => node.parent;
+  Iterable<SnapshotObject> getChildren(SnapshotObject node) => node.children;
+  void onSelect(SnapshotObject node) {
+    element.selection = node.objects;
+    element._r.dirty();
+  }
+
+  void onDetails(SnapshotObject node) {
+    element.selection = node.objects;
+    element._mode = HeapSnapshotTreeMode.successors;
+    element._r.dirty();
+  }
+}
+
+class MergedDominatorTreeMap
+    extends TreeMap<M.HeapSnapshotMergedDominatorNode> {
+  HeapSnapshotElement element;
+  MergedDominatorTreeMap(this.element);
+
+  int getSize(M.HeapSnapshotMergedDominatorNode node) => node.retainedSize;
+  String getType(M.HeapSnapshotMergedDominatorNode node) => node.klass.name;
+  String getLabel(M.HeapSnapshotMergedDominatorNode node) =>
+      (node as dynamic).description;
+  M.HeapSnapshotMergedDominatorNode getParent(
+          M.HeapSnapshotMergedDominatorNode node) =>
+      (node as dynamic).parent;
+  Iterable<M.HeapSnapshotMergedDominatorNode> getChildren(
+          M.HeapSnapshotMergedDominatorNode node) =>
+      node.children;
+  void onSelect(M.HeapSnapshotMergedDominatorNode node) {
+    element.mergedSelection = node;
+    element._r.dirty();
+  }
+
+  void onDetails(M.HeapSnapshotMergedDominatorNode node) {
+    dynamic n = node;
+    element.selection = n.objects;
+    element._mode = HeapSnapshotTreeMode.successors;
+    element._r.dirty();
+  }
+}
+
+// Using `null` to represent the root.
+class ClassesShallowTreeMap extends TreeMap<SnapshotClass> {
+  HeapSnapshotElement element;
+  M.HeapSnapshot snapshot;
+
+  ClassesShallowTreeMap(this.element, this.snapshot);
+
+  int getSize(SnapshotClass node) =>
+      node == null ? snapshot.size : node.shallowSize;
+  String getType(SnapshotClass node) => node == null ? "Classes" : node.name;
+  String getLabel(SnapshotClass node) => node == null
+      ? "${snapshot.classes.length} classes"
+      : "${node.instanceCount} instances of ${node.name}";
+  SnapshotClass getParent(SnapshotClass node) => null;
+  Iterable<SnapshotClass> getChildren(SnapshotClass node) =>
+      node == null ? snapshot.classes : <SnapshotClass>[];
+  void onSelect(SnapshotClass node) {}
+  void onDetails(SnapshotClass node) {
+    element.selection = node.instances.toList();
+    element._mode = HeapSnapshotTreeMode.successors;
+    element._r.dirty();
+  }
+}
+
+// Using `null` to represent the root.
+class ClassesOwnershipTreeMap extends TreeMap<SnapshotClass> {
+  HeapSnapshotElement element;
+  M.HeapSnapshot snapshot;
+
+  ClassesOwnershipTreeMap(this.element, this.snapshot);
+
+  int getSize(SnapshotClass node) =>
+      node == null ? snapshot.size : node.ownedSize;
+  String getType(SnapshotClass node) => node == null ? "classes" : node.name;
+  String getLabel(SnapshotClass node) => node == null
+      ? "${snapshot.classes.length} Classes"
+      : "${node.instanceCount} instances of ${node.name}";
+  SnapshotClass getParent(SnapshotClass node) => null;
+  Iterable<SnapshotClass> getChildren(SnapshotClass node) =>
+      node == null ? snapshot.classes : <SnapshotClass>[];
+  void onSelect(SnapshotClass node) {}
+  void onDetails(SnapshotClass node) {
+    element.selection = node.instances.toList();
+    element._mode = HeapSnapshotTreeMode.successors;
+    element._r.dirty();
+  }
 }
 
 class HeapSnapshotElement extends CustomElement implements Renderable {
@@ -184,7 +284,7 @@
   }
 
   _save() async {
-    var blob = new Blob(_snapshot.chunks, 'application/octet-stream');
+    var blob = new Blob([_snapshot.encoded], 'application/octet-stream');
     var blobUrl = Url.createObjectUrl(blob);
     var link = new AnchorElement();
     link.href = blobUrl;
@@ -201,10 +301,9 @@
       var file = input.files[0];
       var reader = new FileReader();
       reader.onLoad.listen((event) async {
-        Uint8List blob = reader.result;
-        var chunks = [new ByteData.view(blob.buffer)];
+        Uint8List encoded = reader.result;
         var snapshot = new S.HeapSnapshot();
-        await snapshot.loadProgress(null, chunks).last;
+        await snapshot.loadProgress(null, encoded).last;
         _snapshot = snapshot;
         selection = null;
         mergedSelection = null;
@@ -298,7 +397,7 @@
         ]);
         break;
       case HeapSnapshotTreeMode.dominatorTreeMap:
-        var content = new DivElement();
+        final content = new DivElement();
         content.style.border = '1px solid black';
         content.style.width = '100%';
         content.style.height = '100%';
@@ -310,7 +409,7 @@
           if (selection == null) {
             selection = _snapshot.root.objects;
           }
-          _showTreemap(selection.first, content);
+          new DominatorTreeMap(this).showIn(selection.first, content);
         });
 
         final text =
@@ -342,7 +441,7 @@
         ]);
         break;
       case HeapSnapshotTreeMode.mergedDominatorTreeMap:
-        var content = new DivElement();
+        final content = new DivElement();
         content.style.border = '1px solid black';
         content.style.width = '100%';
         content.style.height = '100%';
@@ -354,7 +453,7 @@
           if (mergedSelection == null) {
             mergedSelection = _snapshot.mergedDominatorTree;
           }
-          _showTreemap(mergedSelection, content);
+          new MergedDominatorTreeMap(this).showIn(mergedSelection, content);
         });
 
         final text =
@@ -388,6 +487,33 @@
           _tree.element
         ]);
         break;
+      case HeapSnapshotTreeMode.ownershipTreeMap:
+        final content = new DivElement();
+        content.style.border = '1px solid black';
+        content.style.width = '100%';
+        content.style.height = '100%';
+        content.text = 'Performing layout...';
+        Timer.run(() {
+          // Generate the treemap after the content div has been added to the
+          // document so that we can ask the browser how much space is
+          // available for treemap layout.
+          new ClassesOwnershipTreeMap(this, _snapshot).showIn(null, content);
+        });
+        final text = 'An object X is said to "own" object Y if X is the only '
+            'object that references Y, or X owns the only object that '
+            'references Y. In particular, objects "own" the space of any '
+            'unshared lists or maps they reference.';
+        report.addAll([
+          new DivElement()
+            ..classes = ['content-centered-big', 'explanation']
+            ..text = text,
+          new DivElement()
+            ..classes = ['content-centered-big']
+            ..style.width = '100%'
+            ..style.height = '100%'
+            ..children = [content]
+        ]);
+        break;
       case HeapSnapshotTreeMode.successors:
         if (selection == null) {
           selection = _snapshot.root.objects;
@@ -424,7 +550,7 @@
           _tree.element
         ]);
         break;
-      case HeapSnapshotTreeMode.classes:
+      case HeapSnapshotTreeMode.classesTable:
         final items = _snapshot.classes.toList();
         items.sort((a, b) => b.shallowSize - a.shallowSize);
         _tree = new VirtualTreeElement(
@@ -432,7 +558,26 @@
             items: items, queue: _r.queue);
         report.add(_tree.element);
         break;
-
+      case HeapSnapshotTreeMode.classesTreeMap:
+        final content = new DivElement();
+        content.style.border = '1px solid black';
+        content.style.width = '100%';
+        content.style.height = '100%';
+        content.text = 'Performing layout...';
+        Timer.run(() {
+          // Generate the treemap after the content div has been added to the
+          // document so that we can ask the browser how much space is
+          // available for treemap layout.
+          new ClassesShallowTreeMap(this, _snapshot).showIn(null, content);
+        });
+        report.addAll([
+          new DivElement()
+            ..classes = ['content-centered-big']
+            ..style.width = '100%'
+            ..style.height = '100%'
+            ..children = [content]
+        ]);
+        break;
       default:
         break;
     }
@@ -734,198 +879,6 @@
     element.children[5].text = node.name;
   }
 
-  String color(String string) {
-    int hue = string.hashCode % 360;
-    return "hsl($hue,60%,60%)";
-  }
-
-  String prettySize(num size) {
-    if (size < 1024) return size.toStringAsFixed(0) + "B";
-    size /= 1024;
-    if (size < 1024) return size.toStringAsFixed(1) + "KiB";
-    size /= 1024;
-    if (size < 1024) return size.toStringAsFixed(1) + "MiB";
-    size /= 1024;
-    return size.toStringAsFixed(1) + "GiB";
-  }
-
-  /* SnapshotObject | M.MergedDominatorNode */
-  void _showTreemap(dynamic node, DivElement content) {
-    final w = content.offsetWidth.toDouble();
-    final h = content.offsetHeight.toDouble();
-    final topTile = _createTreemapTile(node, w, h, 0, content);
-    topTile.style.width = "${w}px";
-    topTile.style.height = "${h}px";
-    topTile.style.border = "none";
-    content.children = [topTile];
-  }
-
-  Element _createTreemapTile(dynamic node, double width, double height,
-      int depth, DivElement content) {
-    final div = new DivElement();
-    div.className = "treemapTile";
-    div.style.backgroundColor = color(node.klass.name);
-    div.onDoubleClick.listen((event) {
-      event.stopPropagation();
-      if (depth == 0) {
-        // Zoom out.
-        if (node is SnapshotObject) {
-          selection = node.parent.objects;
-        } else {
-          mergedSelection = node.parent;
-        }
-      } else {
-        // Zoom in.
-        if (node is SnapshotObject) {
-          selection = node.objects;
-        } else {
-          mergedSelection = node;
-        }
-      }
-      _r.dirty();
-    });
-    div.onContextMenu.listen((event) {
-      event.stopPropagation();
-      if (node is SnapshotObject) {
-        selection = node.objects;
-        _mode = HeapSnapshotTreeMode.successors;
-      } else {
-        selection = node.objects;
-        _mode = HeapSnapshotTreeMode.successors;
-      }
-      _r.dirty();
-    });
-
-    double left = 0.0;
-    double top = 0.0;
-
-    const kPadding = 5;
-    const kBorder = 1;
-    left += kPadding - kBorder;
-    top += kPadding - kBorder;
-    width -= 2 * kPadding;
-    height -= 2 * kPadding;
-
-    final label = "${node.description} [${prettySize(node.retainedSize)}]";
-    div.title = label; // I.e., tooltip.
-
-    if (width < 10 || height < 10) {
-      // Too small: don't render label or children.
-      return div;
-    }
-
-    div.append(new SpanElement()..text = label);
-    const kLabelHeight = 9.0;
-    top += kLabelHeight;
-    height -= kLabelHeight;
-
-    if (depth > 2) {
-      // Too deep: don't render children.
-      return div;
-    }
-    if (width < 4 || height < 4) {
-      // Too small: don't render children.
-      return div;
-    }
-
-    final children = new List<dynamic>();
-    for (var c in node.children) {
-      // Size 0 children seem to confuse the layout algorithm (accumulating
-      // rounding errors?).
-      if (c.retainedSize > 0) {
-        children.add(c);
-      }
-    }
-    children.sort((a, b) => b.retainedSize - a.retainedSize);
-
-    final double scale = width * height / node.retainedSize;
-
-    // Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
-    // Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
-    // Springer, Vienna.
-    for (int rowStart = 0; // Index of first child in the next row.
-        rowStart < children.length;) {
-      // Prefer wider rectangles, the better to fit text labels.
-      const double GOLDEN_RATIO = 1.61803398875;
-      final bool verticalSplit = (width / height) > GOLDEN_RATIO;
-
-      double space;
-      if (verticalSplit) {
-        space = height;
-      } else {
-        space = width;
-      }
-
-      double rowMin = children[rowStart].retainedSize * scale;
-      double rowMax = rowMin;
-      double rowSum = 0.0;
-      double lastRatio = 0.0;
-
-      int rowEnd; // One after index of last child in the next row.
-      for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
-        double size = children[rowEnd].retainedSize * scale;
-        if (size < rowMin) rowMin = size;
-        if (size > rowMax) rowMax = size;
-        rowSum += size;
-
-        double ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
-            (rowSum * rowSum) / (space * space * rowMin));
-        if ((lastRatio != 0) && (ratio > lastRatio)) {
-          // Adding the next child makes the aspect ratios worse: remove it and
-          // add the row.
-          rowSum -= size;
-          break;
-        }
-        lastRatio = ratio;
-      }
-
-      double rowLeft = left;
-      double rowTop = top;
-      double rowSpace = rowSum / space;
-
-      for (var i = rowStart; i < rowEnd; i++) {
-        var child = children[i];
-        double size = child.retainedSize * scale;
-
-        double childWidth;
-        double childHeight;
-        if (verticalSplit) {
-          childWidth = rowSpace;
-          childHeight = size / childWidth;
-        } else {
-          childHeight = rowSpace;
-          childWidth = size / childHeight;
-        }
-
-        var childDiv = _createTreemapTile(
-            child, childWidth, childHeight, depth + 1, content);
-        childDiv.style.left = "${rowLeft}px";
-        childDiv.style.top = "${rowTop}px";
-        // Oversize the final div by kBorder to make the borders overlap.
-        childDiv.style.width = "${childWidth + kBorder}px";
-        childDiv.style.height = "${childHeight + kBorder}px";
-        div.append(childDiv);
-
-        if (verticalSplit)
-          rowTop += childHeight;
-        else
-          rowLeft += childWidth;
-      }
-
-      if (verticalSplit) {
-        left += rowSpace;
-        width -= rowSpace;
-      } else {
-        top += rowSpace;
-        height -= rowSpace;
-      }
-
-      rowStart = rowEnd;
-    }
-
-    return div;
-  }
-
   static _updateLines(List<Element> lines, int n) {
     n = Math.max(0, n);
     while (lines.length > n) {
@@ -947,13 +900,17 @@
       case HeapSnapshotTreeMode.mergedDominatorTreeMap:
         return 'Dominators (treemap, siblings merged by class)';
       case HeapSnapshotTreeMode.ownershipTable:
-        return 'Ownership';
+        return 'Ownership (table)';
+      case HeapSnapshotTreeMode.ownershipTreeMap:
+        return 'Ownership (treemap)';
+      case HeapSnapshotTreeMode.classesTable:
+        return 'Classes (table)';
+      case HeapSnapshotTreeMode.classesTreeMap:
+        return 'Classes (treemap)';
       case HeapSnapshotTreeMode.successors:
         return 'Successors / outgoing references';
       case HeapSnapshotTreeMode.predecessors:
         return 'Predecessors / incoming references';
-      case HeapSnapshotTreeMode.classes:
-        return 'Classes';
     }
     throw new Exception('Unknown HeapSnapshotTreeMode: $mode');
   }
diff --git a/runtime/observatory/lib/src/elements/native_memory_profiler.dart b/runtime/observatory/lib/src/elements/native_memory_profiler.dart
index 8936b31..4d874b5 100644
--- a/runtime/observatory/lib/src/elements/native_memory_profiler.dart
+++ b/runtime/observatory/lib/src/elements/native_memory_profiler.dart
@@ -106,7 +106,7 @@
             selectedTag: _tag, queue: _r.queue)
           ..onTagChange.listen((e) {
             _tag = e.element.selectedTag;
-            _request(forceFetch: true);
+            _request();
           }))
         .element);
     if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
@@ -145,9 +145,6 @@
   }
 
   Future _request({bool forceFetch: false}) async {
-    for (M.Isolate isolate in _vm.isolates) {
-      await isolate.collectAllGarbage();
-    }
     _progress = null;
     _progressStream = _profiles.get(_vm, _tag, forceFetch: forceFetch);
     _r.dirty();
diff --git a/runtime/observatory/lib/src/elements/nav/reload.dart b/runtime/observatory/lib/src/elements/nav/reload.dart
index 64534d3..b6d1a5c 100644
--- a/runtime/observatory/lib/src/elements/nav/reload.dart
+++ b/runtime/observatory/lib/src/elements/nav/reload.dart
@@ -35,9 +35,9 @@
   factory NavReloadElement(M.IsolateRef isolate, M.IsolateRepository isolates,
       M.EventRepository events,
       {RenderingQueue queue}) {
-    assert(isolate == null);
-    assert(isolates == null);
-    assert(events == null);
+    assert(isolate != null);
+    assert(isolates != null);
+    assert(events != null);
     NavReloadElement e = new NavReloadElement.created();
     e._r = new RenderingScheduler<NavReloadElement>(e, queue: queue);
     e._isolate = isolate;
diff --git a/runtime/observatory/lib/src/elements/sample_buffer_control.dart b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
index 97adb22..10ba12f 100644
--- a/runtime/observatory/lib/src/elements/sample_buffer_control.dart
+++ b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
@@ -160,7 +160,7 @@
     final loadT = Utils.formatDurationInSeconds(_progress.loadingTime);
     final sampleCount = _progress.profile.sampleCount;
     final refreshT = new DateTime.now();
-    final stackDepth = _progress.profile.stackDepth;
+    final maxStackDepth = _progress.profile.maxStackDepth;
     final sampleRate = _progress.profile.sampleRate.toStringAsFixed(0);
     final timeSpan = _progress.profile.sampleCount == 0
         ? '0s'
@@ -195,7 +195,7 @@
             ..text = 'Sampling',
           new DivElement()
             ..classes = ['memberValue']
-            ..text = '$stackDepth stack frames @ ${sampleRate}Hz'
+            ..text = '$maxStackDepth stack frames @ ${sampleRate}Hz'
         ],
     ];
     if (_showTag) {
diff --git a/runtime/observatory/lib/src/elements/timeline/dashboard.dart b/runtime/observatory/lib/src/elements/timeline/dashboard.dart
index 584d8b8..8995be8 100644
--- a/runtime/observatory/lib/src/elements/timeline/dashboard.dart
+++ b/runtime/observatory/lib/src/elements/timeline/dashboard.dart
@@ -208,9 +208,9 @@
   Future _refresh() async {
     _flags = await _repository.getFlags(vm);
     _r.dirty();
-    final params =
-        new Map<String, dynamic>.from(await _repository.getIFrameParams(vm));
-    return _postMessage('refresh', params);
+    final traceData =
+        Map<String, dynamic>.from(await _repository.getTimeline(vm));
+    return _postMessage('refresh', traceData);
   }
 
   Future _clear() async {
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index f912239..7e54388 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -232,9 +232,8 @@
   }
 
   Future _refresh() async {
-    final params =
-        new Map<String, dynamic>.from(await _repository.getIFrameParams(vm));
-    return _postMessage('refresh', params);
+    final traceData = await _repository.getTimeline(vm);
+    return _postMessage('refresh', traceData);
   }
 
   Future _clear() async {
diff --git a/runtime/observatory/lib/src/elements/tree_map.dart b/runtime/observatory/lib/src/elements/tree_map.dart
new file mode 100644
index 0000000..8db1728
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/tree_map.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:math' as Math;
+
+String _color(String string) {
+  int hue = string.hashCode % 360;
+  return "hsl($hue,60%,60%)";
+}
+
+String _prettySize(num size) {
+  if (size < 1024) return size.toStringAsFixed(0) + "B";
+  size /= 1024;
+  if (size < 1024) return size.toStringAsFixed(1) + "KiB";
+  size /= 1024;
+  if (size < 1024) return size.toStringAsFixed(1) + "MiB";
+  size /= 1024;
+  return size.toStringAsFixed(1) + "GiB";
+}
+
+abstract class TreeMap<T> {
+  int getSize(T node);
+  String getType(T node);
+  String getLabel(T node);
+  T getParent(T node);
+  Iterable<T> getChildren(T node);
+  void onSelect(T node);
+  void onDetails(T node);
+
+  void showIn(T node, DivElement content) {
+    final w = content.offsetWidth.toDouble();
+    final h = content.offsetHeight.toDouble();
+    final topTile = _createTreemapTile(node, w, h, 0, content);
+    topTile.style.width = "${w}px";
+    topTile.style.height = "${h}px";
+    topTile.style.border = "none";
+    content.children = [topTile];
+  }
+
+  Element _createTreemapTile(
+      T node, double width, double height, int depth, DivElement content) {
+    final div = new DivElement();
+    div.className = "treemapTile";
+    div.style.backgroundColor = _color(getType(node));
+    div.onDoubleClick.listen((event) {
+      event.stopPropagation();
+      if (depth == 0) {
+        onSelect(getParent(node)); // Zoom out.
+      } else {
+        onSelect(node); // Zoom in.
+      }
+    });
+    div.onContextMenu.listen((event) {
+      event.stopPropagation();
+      onDetails(node);
+    });
+
+    double left = 0.0;
+    double top = 0.0;
+
+    const kPadding = 5;
+    const kBorder = 1;
+    left += kPadding - kBorder;
+    top += kPadding - kBorder;
+    width -= 2 * kPadding;
+    height -= 2 * kPadding;
+
+    final label = "${getLabel(node)} [${_prettySize(getSize(node))}]";
+    div.title = label; // I.e., tooltip.
+
+    if (width < 10 || height < 10) {
+      // Too small: don't render label or children.
+      return div;
+    }
+
+    div.append(new SpanElement()..text = label);
+    const kLabelHeight = 9.0;
+    top += kLabelHeight;
+    height -= kLabelHeight;
+
+    if (depth > 2) {
+      // Too deep: don't render children.
+      return div;
+    }
+    if (width < 4 || height < 4) {
+      // Too small: don't render children.
+      return div;
+    }
+
+    final children = <T>[];
+    for (T c in getChildren(node)) {
+      // Size 0 children seem to confuse the layout algorithm (accumulating
+      // rounding errors?).
+      if (getSize(c) > 0) {
+        children.add(c);
+      }
+    }
+    children.sort((a, b) => getSize(b) - getSize(a));
+
+    final double scale = width * height / getSize(node);
+
+    // Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
+    // Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
+    // Springer, Vienna.
+    for (int rowStart = 0; // Index of first child in the next row.
+        rowStart < children.length;) {
+      // Prefer wider rectangles, the better to fit text labels.
+      const double GOLDEN_RATIO = 1.61803398875;
+      final bool verticalSplit = (width / height) > GOLDEN_RATIO;
+
+      double space;
+      if (verticalSplit) {
+        space = height;
+      } else {
+        space = width;
+      }
+
+      double rowMin = getSize(children[rowStart]) * scale;
+      double rowMax = rowMin;
+      double rowSum = 0.0;
+      double lastRatio = 0.0;
+
+      int rowEnd; // One after index of last child in the next row.
+      for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
+        double size = getSize(children[rowEnd]) * scale;
+        if (size < rowMin) rowMin = size;
+        if (size > rowMax) rowMax = size;
+        rowSum += size;
+
+        double ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
+            (rowSum * rowSum) / (space * space * rowMin));
+        if ((lastRatio != 0) && (ratio > lastRatio)) {
+          // Adding the next child makes the aspect ratios worse: remove it and
+          // add the row.
+          rowSum -= size;
+          break;
+        }
+        lastRatio = ratio;
+      }
+
+      double rowLeft = left;
+      double rowTop = top;
+      double rowSpace = rowSum / space;
+
+      for (int i = rowStart; i < rowEnd; i++) {
+        T child = children[i];
+        double size = getSize(child) * scale;
+
+        double childWidth;
+        double childHeight;
+        if (verticalSplit) {
+          childWidth = rowSpace;
+          childHeight = size / childWidth;
+        } else {
+          childHeight = rowSpace;
+          childWidth = size / childHeight;
+        }
+
+        Element childDiv = _createTreemapTile(
+            child, childWidth, childHeight, depth + 1, content);
+        childDiv.style.left = "${rowLeft}px";
+        childDiv.style.top = "${rowTop}px";
+        // Oversize the final div by kBorder to make the borders overlap.
+        childDiv.style.width = "${childWidth + kBorder}px";
+        childDiv.style.height = "${childHeight + kBorder}px";
+        div.append(childDiv);
+
+        if (verticalSplit)
+          rowTop += childHeight;
+        else
+          rowLeft += childWidth;
+      }
+
+      if (verticalSplit) {
+        left += rowSpace;
+        width -= rowSpace;
+      } else {
+        top += rowSpace;
+        height -= rowSpace;
+      }
+
+      rowStart = rowEnd;
+    }
+
+    return div;
+  }
+}
diff --git a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
index c238385..1c27dbc 100644
--- a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
@@ -15,13 +15,13 @@
   HeapSnapshotMergedDominatorNode mergedDominatorTree;
   List<SnapshotClass> classes;
   SnapshotObject get root => graph.root;
-  List<ByteData> chunks;
+  Uint8List encoded;
 
-  Stream<String> loadProgress(S.Isolate isolate, List<ByteData> chunks) {
+  Stream<String> loadProgress(S.Isolate isolate, Uint8List encoded) {
     final progress = new StreamController<String>.broadcast();
     progress.add('Loading...');
-    this.chunks = chunks;
-    graph = new SnapshotGraph(chunks);
+    this.encoded = encoded;
+    graph = new SnapshotGraph(encoded);
     (() async {
       timestamp = new DateTime.now();
       final stream = graph.process();
diff --git a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
index f6630c0..36ba5ba 100644
--- a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
@@ -10,7 +10,7 @@
   SnapshotObject get root;
   HeapSnapshotMergedDominatorNode get mergedDominatorTree;
   Iterable<SnapshotClass> get classes;
-  List<ByteData> get chunks;
+  Uint8List get encoded;
 }
 
 abstract class HeapSnapshotMergedDominatorNode {
diff --git a/runtime/observatory/lib/src/models/objects/isolate.dart b/runtime/observatory/lib/src/models/objects/isolate.dart
index 039e0bd..f1d1147 100644
--- a/runtime/observatory/lib/src/models/objects/isolate.dart
+++ b/runtime/observatory/lib/src/models/objects/isolate.dart
@@ -14,9 +14,6 @@
 
   /// A name identifying this isolate. Not guaranteed to be unique.
   String get name;
-
-  /// Trigger a full GC, collecting all unreachable or weakly reachable objects.
-  Future collectAllGarbage();
 }
 
 enum IsolateStatus { loading, idle, running, paused }
diff --git a/runtime/observatory/lib/src/models/objects/sample_profile.dart b/runtime/observatory/lib/src/models/objects/sample_profile.dart
index ad0d7be..582e571 100644
--- a/runtime/observatory/lib/src/models/objects/sample_profile.dart
+++ b/runtime/observatory/lib/src/models/objects/sample_profile.dart
@@ -8,11 +8,11 @@
 
 abstract class SampleProfile {
   int get sampleCount;
-  int get stackDepth;
+  int get maxStackDepth;
   double get sampleRate;
   double get timeSpan;
-  Iterable<ProfileCode> get codes;
-  Iterable<ProfileFunction> get functions;
+  List<ProfileCode> get codes;
+  List<ProfileFunction> get functions;
 
   FunctionCallTree loadFunctionTree(ProfileTreeDirection direction);
   CodeCallTree loadCodeTree(ProfileTreeDirection direction);
@@ -21,6 +21,8 @@
 abstract class Profile {
   double get normalizedExclusiveTicks;
   double get normalizedInclusiveTicks;
+  void clearTicks();
+  void tickTag();
 }
 
 abstract class ProfileCode extends Profile {
@@ -31,6 +33,7 @@
 
 abstract class ProfileFunction extends Profile {
   FunctionRef get function;
+  String get resolvedUrl;
   Map<ProfileFunction, int> get callers;
   Map<ProfileFunction, int> get callees;
 }
@@ -53,9 +56,13 @@
 
 abstract class CallTreeNode {
   double get percentage;
+  int get count;
   int get inclusiveNativeAllocations;
   int get exclusiveNativeAllocations;
   Iterable<CallTreeNode> get children;
+  void sortChildren();
+
+  void tick(Map sample, {bool exclusive = false});
 }
 
 abstract class CodeCallTreeNode extends CallTreeNode {
diff --git a/runtime/observatory/lib/src/models/repositories/timeline.dart b/runtime/observatory/lib/src/models/repositories/timeline.dart
index bd8276e..3d528c9 100644
--- a/runtime/observatory/lib/src/models/repositories/timeline.dart
+++ b/runtime/observatory/lib/src/models/repositories/timeline.dart
@@ -8,5 +8,5 @@
   Future<TimelineFlags> getFlags(VMRef ref);
   Future setRecordedStreams(VMRef ref, Iterable<TimelineStream> streams);
   Future clear(VMRef ref);
-  Future<Map<String, dynamic>> getIFrameParams(VMRef ref);
+  Future<Map> getTimeline(VMRef ref);
 }
diff --git a/runtime/observatory/lib/src/repositories/isolate.dart b/runtime/observatory/lib/src/repositories/isolate.dart
index d86365c..68b8ae1 100644
--- a/runtime/observatory/lib/src/repositories/isolate.dart
+++ b/runtime/observatory/lib/src/repositories/isolate.dart
@@ -11,7 +11,7 @@
       _vm.services.where((S.Service s) => s.service == 'reloadSources');
 
   IsolateRepository(this._vm) {
-    assert(_vm == null);
+    assert(_vm != null);
   }
 
   Future<M.Isolate> get(M.IsolateRef i) async {
diff --git a/runtime/observatory/lib/src/repositories/sample_profile.dart b/runtime/observatory/lib/src/repositories/sample_profile.dart
index 27d03c5..944eaba 100644
--- a/runtime/observatory/lib/src/repositories/sample_profile.dart
+++ b/runtime/observatory/lib/src/repositories/sample_profile.dart
@@ -4,22 +4,6 @@
 
 part of repositories;
 
-String _tagToString(M.SampleProfileTag tag) {
-  switch (tag) {
-    case M.SampleProfileTag.userVM:
-      return 'UserVM';
-    case M.SampleProfileTag.userOnly:
-      return 'UserOnly';
-    case M.SampleProfileTag.vmUser:
-      return 'VMUser';
-    case M.SampleProfileTag.vmOnly:
-      return 'VMOnly';
-    case M.SampleProfileTag.none:
-      return 'None';
-  }
-  throw new Exception('Unknown SampleProfileTag: $tag');
-}
-
 class SampleProfileLoadingProgressEvent
     implements M.SampleProfileLoadingProgressEvent {
   final SampleProfileLoadingProgress progress;
@@ -28,7 +12,7 @@
 
 class SampleProfileLoadingProgress extends M.SampleProfileLoadingProgress {
   StreamController<SampleProfileLoadingProgressEvent> _onProgress =
-      new StreamController<SampleProfileLoadingProgressEvent>.broadcast();
+      StreamController<SampleProfileLoadingProgressEvent>.broadcast();
   Stream<SampleProfileLoadingProgressEvent> get onProgress =>
       _onProgress.stream;
 
@@ -40,8 +24,8 @@
 
   M.SampleProfileLoadingStatus _status = M.SampleProfileLoadingStatus.fetching;
   double _progress = 0.0;
-  final Stopwatch _fetchingTime = new Stopwatch();
-  final Stopwatch _loadingTime = new Stopwatch();
+  final _fetchingTime = Stopwatch();
+  final _loadingTime = Stopwatch();
   SampleProfile _profile;
 
   M.SampleProfileLoadingStatus get status => _status;
@@ -59,21 +43,20 @@
     _fetchingTime.start();
     try {
       if (clear && (type == M.SampleProfileType.cpu)) {
-        await owner.invokeRpc('_clearCpuProfile', {});
+        await owner.invokeRpc('clearCpuSamples', {});
       }
 
       var response;
       if (type == M.SampleProfileType.cpu) {
         response = cls != null
-            ? await cls.getAllocationSamples(_tagToString(tag))
-            : await owner
-                .invokeRpc('_getCpuProfile', {'tags': _tagToString(tag)});
+            ? await cls.getAllocationSamples()
+            : await owner.invokeRpc('getCpuSamples', {'_code': true});
       } else if (type == M.SampleProfileType.memory) {
         assert(owner is M.VM);
-        response = await owner.invokeRpc(
-            '_getNativeAllocationSamples', {'tags': _tagToString(tag)});
+        response = await owner
+            .invokeRpc('_getNativeAllocationSamples', {'_code': true});
       } else {
-        throw new Exception('Unknown M.SampleProfileType: $type');
+        throw Exception('Unknown M.SampleProfileType: $type');
       }
 
       _fetchingTime.stop();
@@ -81,8 +64,7 @@
       _status = M.SampleProfileLoadingStatus.loading;
       _triggerOnProgress();
 
-      SampleProfile profile = new SampleProfile();
-
+      SampleProfile profile = SampleProfile();
       Stream<double> progress = profile.loadProgress(owner, response);
       progress.listen((value) {
         _progress = value;
@@ -91,6 +73,7 @@
 
       await progress.drain();
 
+      profile.tagOrder = tag;
       profile.buildFunctionCallerAndCallees();
       _profile = profile;
 
@@ -111,14 +94,15 @@
   }
 
   void _triggerOnProgress() {
-    _onProgress.add(new SampleProfileLoadingProgressEvent(this));
+    _onProgress.add(SampleProfileLoadingProgressEvent(this));
   }
 
-  void reuse() {
+  void reuse(M.SampleProfileTag t) {
+    _profile.tagOrder = t;
     final onProgress =
-        new StreamController<SampleProfileLoadingProgressEvent>.broadcast();
+        StreamController<SampleProfileLoadingProgressEvent>.broadcast();
     Timer.run(() {
-      onProgress.add(new SampleProfileLoadingProgressEvent(this));
+      onProgress.add(SampleProfileLoadingProgressEvent(this));
       onProgress.close();
     });
     _onProgress = onProgress;
@@ -137,9 +121,9 @@
     S.Isolate isolate = i as S.Isolate;
     assert(isolate != null);
     if ((_last != null) && !clear && !forceFetch && (_last.owner == isolate)) {
-      _last.reuse();
+      _last.reuse(t);
     } else {
-      _last = new SampleProfileLoadingProgress(isolate, t, clear);
+      _last = SampleProfileLoadingProgress(isolate, t, clear);
     }
     return _last.onProgress;
   }
@@ -153,8 +137,7 @@
     S.Class cls = c as S.Class;
     assert(isolate != null);
     assert(cls != null);
-    return new SampleProfileLoadingProgress(isolate, t, false, cls: cls)
-        .onProgress;
+    return SampleProfileLoadingProgress(isolate, t, false, cls: cls).onProgress;
   }
 
   Future enable(M.IsolateRef i, M.ClassRef c) {
@@ -180,10 +163,10 @@
     S.VM owner = vm as S.VM;
     assert(owner != null);
 
-    if ((_last != null) && !forceFetch) {
-      _last.reuse();
+    if ((_last != null) && (_last.profile != null) && !forceFetch) {
+      _last.reuse(t);
     } else {
-      _last = new SampleProfileLoadingProgress(owner, t, false,
+      _last = SampleProfileLoadingProgress(owner, t, false,
           type: M.SampleProfileType.memory);
     }
     return _last.onProgress;
diff --git a/runtime/observatory/lib/src/repositories/timeline.dart b/runtime/observatory/lib/src/repositories/timeline.dart
index c2695ef..7c0e4a7 100644
--- a/runtime/observatory/lib/src/repositories/timeline.dart
+++ b/runtime/observatory/lib/src/repositories/timeline.dart
@@ -4,7 +4,11 @@
 
 part of repositories;
 
-class TimelineRepository implements M.TimelineRepository {
+class TimelineRepository extends TimelineRepositoryBase
+    implements M.TimelineRepository {
+  static const _kStackFrames = 'stackFrames';
+  static const _kTraceEvents = 'traceEvents';
+
   Future<M.TimelineFlags> getFlags(M.VMRef ref) async {
     S.VM vm = ref as S.VM;
     S.ServiceMap response = await vm.invokeRpc('getVMTimelineFlags', {});
@@ -24,15 +28,52 @@
     return vm.invokeRpc('clearVMTimeline', {});
   }
 
-  Future<Map<String, dynamic>> getIFrameParams(M.VMRef ref) async {
-    final SH.WebSocketVM vm = ref as SH.WebSocketVM;
-    assert(vm != null);
-    await vm.reload();
-    await vm.reloadIsolates();
+  Future<void> _formatSamples(
+      M.Isolate isolate, Map traceObject, S.ServiceMap cpuSamples) async {
+    const kRootFrameId = 0;
+    final profile = SampleProfile();
+    await profile.load(isolate as S.ServiceObjectOwner, cpuSamples);
+    final trie = profile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
+    final root = trie.root;
+    int nextId = kRootFrameId;
+    processFrame(FunctionCallTreeNode current, FunctionCallTreeNode parent) {
+      int id = nextId;
+      ++nextId;
+      current.frameId = id;
+      // Skip the root.
+      if (id != kRootFrameId) {
+        final function = current.profileFunction.function;
+        final key = '${isolate.id}-$id';
+        traceObject[_kStackFrames][key] = {
+          'category': 'Dart',
+          'name': function.qualifiedName,
+          'resolvedUrl': current.profileFunction.resolvedUrl,
+          if (parent != null && parent.frameId != kRootFrameId)
+            'parent': '${isolate.id}-${parent.frameId}',
+        };
+      }
 
-    return <String, dynamic>{
-      'vmAddress': vm.target.networkAddress,
-      'isolateIds': vm.isolates.map((i) => i.id).toList()
-    };
+      for (final child in current.children) {
+        processFrame(child, current);
+      }
+    }
+
+    processFrame(root, null);
+
+    for (final sample in profile.samples) {
+      FunctionCallTreeNode trie = sample[SampleProfile.kTimelineFunctionTrie];
+
+      if (trie.frameId != kRootFrameId) {
+        traceObject[_kTraceEvents].add({
+          'ph': 'P', // kind = sample event
+          'name': '', // Blank to keep about:tracing happy
+          'pid': profile.pid,
+          'tid': sample['tid'],
+          'ts': sample['timestamp'],
+          'cat': 'Dart',
+          'sf': '${isolate.id}-${trie.frameId}',
+        });
+      }
+    }
   }
 }
diff --git a/runtime/observatory/lib/src/repositories/timeline_base.dart b/runtime/observatory/lib/src/repositories/timeline_base.dart
new file mode 100644
index 0000000..9f6e113
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/timeline_base.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+import 'dart:async';
+import 'package:observatory/sample_profile.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/service.dart' as S;
+
+class TimelineRepositoryBase {
+  static const _kStackFrames = 'stackFrames';
+  static const _kTraceEvents = 'traceEvents';
+  static const kTimeOriginMicros = 'timeOriginMicros';
+  static const kTimeExtentMicros = 'timeExtentMicros';
+
+  Future<void> _formatSamples(
+      M.Isolate isolate, Map traceObject, S.ServiceMap cpuSamples) async {
+    const kRootFrameId = 0;
+    final profile = SampleProfile();
+    await profile.load(isolate as S.ServiceObjectOwner, cpuSamples);
+    final trie = profile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
+    final root = trie.root;
+    int nextId = kRootFrameId;
+    processFrame(FunctionCallTreeNode current, FunctionCallTreeNode parent) {
+      int id = nextId;
+      ++nextId;
+      current.frameId = id;
+      // Skip the root.
+      if (id != kRootFrameId) {
+        final function = current.profileFunction.function;
+        final key = '${isolate.id}-$id';
+        traceObject[_kStackFrames][key] = {
+          'category': 'Dart',
+          'name': function.qualifiedName,
+          'resolvedUrl': current.profileFunction.resolvedUrl,
+          if (parent != null && parent.frameId != kRootFrameId)
+            'parent': '${isolate.id}-${parent.frameId}',
+        };
+      }
+
+      for (final child in current.children) {
+        processFrame(child, current);
+      }
+    }
+
+    processFrame(root, null);
+
+    for (final sample in profile.samples) {
+      FunctionCallTreeNode trie = sample[SampleProfile.kTimelineFunctionTrie];
+
+      if (trie.frameId != kRootFrameId) {
+        traceObject[_kTraceEvents].add({
+          'ph': 'P', // kind = sample event
+          'name': '', // Blank to keep about:tracing happy
+          'pid': profile.pid,
+          'tid': sample['tid'],
+          'ts': sample['timestamp'],
+          'cat': 'Dart',
+          'sf': '${isolate.id}-${trie.frameId}',
+        });
+      }
+    }
+  }
+
+  Future<Map> getCpuProfileTimeline(M.VMRef ref,
+      {int timeOriginMicros, int timeExtentMicros}) async {
+    final S.VM vm = ref as S.VM;
+    final sampleRequests = <Future>[];
+
+    for (final isolate in vm.isolates) {
+      sampleRequests.add(vm.invokeRpc('getCpuSamples', {
+        'isolateId': isolate.id,
+        if (timeOriginMicros != null) kTimeOriginMicros: timeOriginMicros,
+        if (timeExtentMicros != null) kTimeExtentMicros: timeExtentMicros,
+      }));
+    }
+
+    final completed = await Future.wait(sampleRequests);
+    final traceObject = <String, dynamic>{
+      _kStackFrames: {},
+      _kTraceEvents: [],
+    };
+    for (int i = 0; i < vm.isolates.length; ++i) {
+      await _formatSamples(vm.isolates[i], traceObject, completed[i]);
+    }
+    return traceObject;
+  }
+
+  Future<Map> getTimeline(M.VMRef ref) async {
+    final S.VM vm = ref as S.VM;
+    final S.ServiceMap vmTimelineResponse =
+        await vm.invokeRpc('getVMTimeline', {});
+    final timeOriginMicros = vmTimelineResponse[kTimeOriginMicros];
+    final timeExtentMicros = vmTimelineResponse[kTimeExtentMicros];
+    final traceObject = await getCpuProfileTimeline(
+      vm,
+      timeOriginMicros: timeOriginMicros,
+      timeExtentMicros: timeExtentMicros,
+    );
+    traceObject[_kTraceEvents].addAll(vmTimelineResponse[_kTraceEvents]);
+    return traceObject;
+  }
+}
diff --git a/runtime/observatory/lib/src/sample_profile/sample_profile.dart b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
index 177713b..48667cc 100644
--- a/runtime/observatory/lib/src/sample_profile/sample_profile.dart
+++ b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
@@ -7,36 +7,90 @@
 abstract class CallTreeNode<NodeT extends M.CallTreeNode>
     implements M.CallTreeNode {
   final List<NodeT> children;
-  final int count;
-  final int inclusiveNativeAllocations;
-  final int exclusiveNativeAllocations;
+  int get count => _count;
+  int _count = 0;
+  int inclusiveNativeAllocations = 0;
+  int exclusiveNativeAllocations = 0;
   double get percentage => _percentage;
   double _percentage = 0.0;
-  final Set<String> attributes = new Set<String>();
+  final attributes = <String>{};
+
+  // Used for building timeline
+  int frameId = null;
+  int parentId = null;
 
   // Either a ProfileCode or a ProfileFunction.
   Object get profileData;
   String get name;
 
-  CallTreeNode(this.children, this.count, this.inclusiveNativeAllocations,
-      this.exclusiveNativeAllocations);
+  CallTreeNode(this.children,
+      [this._count = 0,
+      this.inclusiveNativeAllocations = 0,
+      this.exclusiveNativeAllocations = 0]) {}
+
+  NodeT getChild(int index);
+
+  void sortChildren() {
+    children.sort((a, b) => b.count - a.count);
+    children.forEach((NodeT child) => child.sortChildren());
+  }
+
+  void tick(Map sample, {bool exclusive = false}) {
+    ++_count;
+    if (SampleProfile._isNativeAllocationSample(sample)) {
+      final allocationSize = sample[SampleProfile._kNativeAllocationSizeBytes];
+      if (exclusive) {
+        exclusiveNativeAllocations += allocationSize;
+      }
+      inclusiveNativeAllocations += allocationSize;
+    }
+  }
 }
 
 class CodeCallTreeNode extends CallTreeNode<CodeCallTreeNode>
     implements M.CodeCallTreeNode {
   final ProfileCode profileCode;
+  final SampleProfile profile;
 
   Object get profileData => profileCode;
 
   String get name => profileCode.code.name;
 
-  final Set<String> attributes = new Set<String>();
+  final attributes = <String>{};
   CodeCallTreeNode(this.profileCode, int count, int inclusiveNativeAllocations,
       int exclusiveNativeAllocations)
-      : super(new List<CodeCallTreeNode>(), count, inclusiveNativeAllocations,
+      : profile = profileCode.profile,
+        super(<CodeCallTreeNode>[], count, inclusiveNativeAllocations,
             exclusiveNativeAllocations) {
     attributes.addAll(profileCode.attributes);
   }
+
+  CodeCallTreeNode.fromIndex(this.profile, int tableIndex)
+      : profileCode = profile.codes[tableIndex],
+        super(<CodeCallTreeNode>[]);
+
+  CodeCallTreeNode getChild(int codeTableIndex) {
+    final length = children.length;
+    int i = 0;
+    while (i < length) {
+      final child = children[i];
+      final childTableIndex = child.profileCode.tableIndex;
+      if (childTableIndex == codeTableIndex) {
+        return child;
+      }
+      if (childTableIndex > codeTableIndex) {
+        break;
+      }
+      ++i;
+    }
+    final child = CodeCallTreeNode.fromIndex(profile, codeTableIndex);
+    if (i < length) {
+      children.insert(i, child);
+    } else {
+      children.add(child);
+    }
+    return child;
+  }
 }
 
 class CallTree<NodeT extends CallTreeNode> {
@@ -58,7 +112,7 @@
   }
 
   CodeCallTree filtered(CallTreeNodeFilter filter) {
-    var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this);
+    final treeFilter = _FilteredCodeCallTreeBuilder(filter, this);
     treeFilter.build();
     if ((treeFilter.filtered.root.inclusiveNativeAllocations != null) &&
         (treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
@@ -137,7 +191,8 @@
 class FunctionCallTreeNode extends CallTreeNode<FunctionCallTreeNode>
     implements M.FunctionCallTreeNode {
   final ProfileFunction profileFunction;
-  final codes = new List<FunctionCallTreeNodeCode>();
+  final SampleProfile profile;
+  final codes = <FunctionCallTreeNodeCode>[];
   int _totalCodeTicks = 0;
   int get totalCodesTicks => _totalCodeTicks;
 
@@ -146,69 +201,43 @@
 
   FunctionCallTreeNode(this.profileFunction, int count,
       inclusiveNativeAllocations, exclusiveNativeAllocations)
-      : super(new List<FunctionCallTreeNode>(), count,
-            inclusiveNativeAllocations, exclusiveNativeAllocations) {
+      : profile = profileFunction.profile,
+        super(<FunctionCallTreeNode>[], count, inclusiveNativeAllocations,
+            exclusiveNativeAllocations) {
     profileFunction._addKindBasedAttributes(attributes);
   }
 
-  // Does this function have an optimized version of itself?
-  bool hasOptimizedCode() {
-    for (var nodeCode in codes) {
-      var profileCode = nodeCode.code;
-      if (!profileCode.code.isDartCode) {
-        continue;
-      }
-      if (profileCode.code.function != profileFunction.function) {
-        continue;
-      }
-      if (profileCode.code.isOptimized) {
-        return true;
-      }
-    }
-    return false;
-  }
+  FunctionCallTreeNode.fromIndex(this.profile, int tableIndex)
+      : profileFunction = profile.functions[tableIndex],
+        super(<FunctionCallTreeNode>[]);
 
-  // Does this function have an unoptimized version of itself?
-  bool hasUnoptimizedCode() {
-    for (var nodeCode in codes) {
-      var profileCode = nodeCode.code;
-      if (!profileCode.code.isDartCode) {
-        continue;
+  FunctionCallTreeNode getChild(int functionTableIndex) {
+    final length = children.length;
+    int i = 0;
+    while (i < length) {
+      final child = children[i];
+      final childTableIndex = child.profileFunction.tableIndex;
+      if (childTableIndex == functionTableIndex) {
+        return child;
       }
-      if (profileCode.code.kind == M.CodeKind.stub) {
-        continue;
+      if (childTableIndex > functionTableIndex) {
+        break;
       }
-      if (!profileCode.code.isOptimized) {
-        return true;
-      }
+      ++i;
     }
-    return false;
-  }
-
-  // Has this function been inlined in another function?
-  bool isInlined() {
-    for (var nodeCode in codes) {
-      var profileCode = nodeCode.code;
-      if (!profileCode.code.isDartCode) {
-        continue;
-      }
-      if (profileCode.code.kind == M.CodeKind.stub) {
-        continue;
-      }
-      // If the code's function isn't this function.
-      if (profileCode.code.function != profileFunction.function) {
-        return true;
-      }
+    final child = FunctionCallTreeNode.fromIndex(profile, functionTableIndex);
+    if (i < length) {
+      children.insert(i, child);
+    } else {
+      children.add(child);
     }
-    return false;
+    return child;
   }
-
-  setCodeAttributes() {}
 }
 
 /// Predicate filter function. Returns true if path from root to [node] and all
 /// of [node]'s children should be added to the filtered tree.
-typedef bool CallTreeNodeFilter(CallTreeNode node);
+typedef CallTreeNodeFilter = bool Function(CallTreeNode node);
 
 /// Build a filter version of a FunctionCallTree.
 abstract class _FilteredCallTreeBuilder<NodeT extends CallTreeNode> {
@@ -263,7 +292,6 @@
         current.children.add(child);
       }
       current = child;
-      assert(current.count == toAdd.count);
     }
     return current;
   }
@@ -328,16 +356,16 @@
       : super(
             filter,
             tree,
-            new FunctionCallTree(
+            FunctionCallTree(
                 tree.inclusive,
-                new FunctionCallTreeNode(
+                FunctionCallTreeNode(
                     tree.root.profileData,
                     tree.root.count,
                     tree.root.inclusiveNativeAllocations,
                     tree.root.exclusiveNativeAllocations)));
 
   _copyNode(FunctionCallTreeNode node) {
-    return new FunctionCallTreeNode(node.profileData, node.count,
+    return FunctionCallTreeNode(node.profileData, node.count,
         node.inclusiveNativeAllocations, node.exclusiveNativeAllocations);
   }
 }
@@ -348,16 +376,16 @@
       : super(
             filter,
             tree,
-            new CodeCallTree(
+            CodeCallTree(
                 tree.inclusive,
-                new CodeCallTreeNode(
+                CodeCallTreeNode(
                     tree.root.profileData,
                     tree.root.count,
                     tree.root.inclusiveNativeAllocations,
                     tree.root.exclusiveNativeAllocations)));
 
   _copyNode(CodeCallTreeNode node) {
-    return new CodeCallTreeNode(node.profileData, node.count,
+    return CodeCallTreeNode(node.profileData, node.count,
         node.inclusiveNativeAllocations, node.exclusiveNativeAllocations);
   }
 }
@@ -375,7 +403,7 @@
   }
 
   FunctionCallTree filtered(CallTreeNodeFilter filter) {
-    var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this);
+    final treeFilter = _FilteredFunctionCallTreeBuilder(filter, this);
     treeFilter.build();
     if ((treeFilter.filtered.root.inclusiveNativeAllocations != null) &&
         (treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
@@ -464,24 +492,21 @@
 }
 
 class ProfileCode implements M.ProfileCode {
+  final int tableIndex;
   final SampleProfile profile;
   final Code code;
   int exclusiveTicks;
   int inclusiveTicks;
-  int exclusiveNativeAllocations;
-  int inclusiveNativeAllocations;
   double normalizedExclusiveTicks = 0.0;
   double normalizedInclusiveTicks = 0.0;
-  final addressTicks = new Map<int, CodeTick>();
-  final intervalTicks = new Map<int, InlineIntervalTick>();
+  final addressTicks = <int, CodeTick>{};
+  final intervalTicks = <int, InlineIntervalTick>{};
   String formattedInclusiveTicks = '';
   String formattedExclusiveTicks = '';
   String formattedExclusivePercent = '';
-  String formattedCpuTime = '';
-  String formattedOnStackTime = '';
-  final Set<String> attributes = new Set<String>();
-  final Map<ProfileCode, int> callers = new Map<ProfileCode, int>();
-  final Map<ProfileCode, int> callees = new Map<ProfileCode, int>();
+  final Set<String> attributes = <String>{};
+  final callers = <ProfileCode, int>{};
+  final callees = <ProfileCode, int>{};
 
   void _processTicks(List<dynamic> profileTicks) {
     assert(profileTicks != null);
@@ -492,7 +517,7 @@
       var address = int.parse(profileTicks[i] as String, radix: 16);
       var exclusive = profileTicks[i + 1] as int;
       var inclusive = profileTicks[i + 2] as int;
-      var tick = new CodeTick(exclusive, inclusive);
+      var tick = CodeTick(exclusive, inclusive);
       addressTicks[address] = tick;
 
       var interval = code.findInterval(address);
@@ -500,7 +525,7 @@
         var intervalTick = intervalTicks[interval.start];
         if (intervalTick == null) {
           // Insert into map.
-          intervalTick = new InlineIntervalTick(interval.start);
+          intervalTick = InlineIntervalTick(interval.start);
           intervalTicks[interval.start] = intervalTick;
         }
         intervalTick._inclusiveTicks += inclusive;
@@ -509,7 +534,17 @@
     }
   }
 
-  ProfileCode.fromMap(this.profile, this.code, Map data) {
+  void clearTicks() {
+    exclusiveTicks = 0;
+    inclusiveTicks = 0;
+    normalizedExclusiveTicks = 0;
+    normalizedInclusiveTicks = 0;
+    formattedInclusiveTicks = '';
+    formattedExclusiveTicks = '';
+    formattedExclusivePercent = '';
+  }
+
+  ProfileCode.fromMap(this.tableIndex, this.profile, this.code, Map data) {
     assert(profile != null);
     assert(code != null);
 
@@ -548,23 +583,9 @@
       _processTicks(ticks);
     }
 
-    if (data.containsKey('exclusiveNativeAllocations') &&
-        data.containsKey('inclusiveNativeAllocations')) {
-      exclusiveNativeAllocations =
-          int.parse(data['exclusiveNativeAllocations']);
-      inclusiveNativeAllocations =
-          int.parse(data['inclusiveNativeAllocations']);
-    }
-
     formattedExclusivePercent =
         Utils.formatPercent(exclusiveTicks, profile.sampleCount);
 
-    formattedCpuTime = Utils.formatTimeMilliseconds(
-        profile.approximateMillisecondsForCount(exclusiveTicks));
-
-    formattedOnStackTime = Utils.formatTimeMilliseconds(
-        profile.approximateMillisecondsForCount(inclusiveTicks));
-
     formattedInclusiveTicks =
         '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
         '($inclusiveTicks)';
@@ -589,15 +610,43 @@
     }
     callees[callee] = r + count;
   }
+
+  void _normalizeTicks() {
+    normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
+    normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
+
+    formattedExclusivePercent =
+        Utils.formatPercent(exclusiveTicks, profile.sampleCount);
+
+    formattedInclusiveTicks =
+        '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
+        '($inclusiveTicks)';
+
+    formattedExclusiveTicks =
+        '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
+        '($exclusiveTicks)';
+  }
+
+  void tickTag() {
+    // All functions *except* those for tags are ticked in the VM while
+    // generating the CpuSamples response.
+    if (code.kind != M.CodeKind.tag) {
+      throw StateError('Only tags should be ticked. '
+          'Attempted to tick: ${code.name}');
+    }
+    ++exclusiveTicks;
+    ++inclusiveTicks;
+    _normalizeTicks();
+  }
 }
 
 class ProfileFunction implements M.ProfileFunction {
+  final int tableIndex;
   final SampleProfile profile;
   final ServiceFunction function;
-  // List of compiled code objects containing this function.
-  final List<ProfileCode> profileCodes = new List<ProfileCode>();
-  final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>();
-  final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>();
+  final String resolvedUrl;
+  final callers = <ProfileFunction, int>{};
+  final callees = <ProfileFunction, int>{};
 
   // Absolute ticks:
   int exclusiveTicks = 0;
@@ -607,71 +656,19 @@
   double normalizedExclusiveTicks = 0.0;
   double normalizedInclusiveTicks = 0.0;
 
-  // Native allocations:
-  int exclusiveNativeAllocations = 0;
-  int inclusiveNativeAllocations = 0;
-
   String formattedInclusiveTicks = '';
   String formattedExclusiveTicks = '';
   String formattedExclusivePercent = '';
-  String formattedCpuTime = '';
-  String formattedOnStackTime = '';
-  final Set<String> attributes = new Set<String>();
+  final attributes = <String>{};
 
-  int _sortCodes(ProfileCode a, ProfileCode b) {
-    if (a.code.isOptimized == b.code.isOptimized) {
-      return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks;
-    }
-    if (a.code.isOptimized) {
-      return -1;
-    }
-    return 1;
-  }
-
-  // Does this function have an optimized version of itself?
-  bool hasOptimizedCode() {
-    for (var profileCode in profileCodes) {
-      if (profileCode.code.function != function) {
-        continue;
-      }
-      if (profileCode.code.isOptimized) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // Does this function have an unoptimized version of itself?
-  bool hasUnoptimizedCode() {
-    for (var profileCode in profileCodes) {
-      if (profileCode.code.kind == M.CodeKind.stub) {
-        continue;
-      }
-      if (!profileCode.code.isDartCode) {
-        continue;
-      }
-      if (!profileCode.code.isOptimized) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // Has this function been inlined in another function?
-  bool isInlined() {
-    for (var profileCode in profileCodes) {
-      if (profileCode.code.kind == M.CodeKind.stub) {
-        continue;
-      }
-      if (!profileCode.code.isDartCode) {
-        continue;
-      }
-      // If the code's function isn't this function.
-      if (profileCode.code.function != function) {
-        return true;
-      }
-    }
-    return false;
+  void clearTicks() {
+    exclusiveTicks = 0;
+    inclusiveTicks = 0;
+    normalizedExclusiveTicks = 0;
+    normalizedInclusiveTicks = 0;
+    formattedInclusiveTicks = '';
+    formattedExclusiveTicks = '';
+    formattedExclusivePercent = '';
   }
 
   void _addKindBasedAttributes(Set<String> attribs) {
@@ -693,45 +690,14 @@
     }
   }
 
-  ProfileFunction.fromMap(this.profile, this.function, Map data) {
+  ProfileFunction.fromMap(
+      this.tableIndex, this.profile, this.function, Map data)
+      : resolvedUrl = data['resolvedUrl'] {
     function.profile = this;
-    for (var codeIndex in data['codes']) {
-      var profileCode = profile.codes[codeIndex];
-      profileCodes.add(profileCode);
-    }
-    profileCodes.sort(_sortCodes);
-
     _addKindBasedAttributes(attributes);
     exclusiveTicks = data['exclusiveTicks'];
     inclusiveTicks = data['inclusiveTicks'];
-
-    normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
-    normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
-
-    if (data.containsKey('exclusiveNativeAllocations') &&
-        data.containsKey('inclusiveNativeAllocations')) {
-      exclusiveNativeAllocations =
-          int.parse(data['exclusiveNativeAllocations']);
-      inclusiveNativeAllocations =
-          int.parse(data['inclusiveNativeAllocations']);
-    }
-
-    formattedExclusivePercent =
-        Utils.formatPercent(exclusiveTicks, profile.sampleCount);
-
-    formattedCpuTime = Utils.formatTimeMilliseconds(
-        profile.approximateMillisecondsForCount(exclusiveTicks));
-
-    formattedOnStackTime = Utils.formatTimeMilliseconds(
-        profile.approximateMillisecondsForCount(inclusiveTicks));
-
-    formattedInclusiveTicks =
-        '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
-        '($inclusiveTicks)';
-
-    formattedExclusiveTicks =
-        '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
-        '($exclusiveTicks)';
+    _normalizeTicks();
   }
 
   _recordCaller(ProfileFunction caller, int count) {
@@ -749,6 +715,34 @@
     }
     callees[callee] = r + count;
   }
+
+  void _normalizeTicks() {
+    normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
+    normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
+
+    formattedExclusivePercent =
+        Utils.formatPercent(exclusiveTicks, profile.sampleCount);
+
+    formattedInclusiveTicks =
+        '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
+        '($inclusiveTicks)';
+
+    formattedExclusiveTicks =
+        '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
+        '($exclusiveTicks)';
+  }
+
+  void tickTag() {
+    // All functions *except* those for functions are ticked in the VM while
+    // generating the CpuSamples response.
+    if (function.kind != M.FunctionKind.tag) {
+      throw StateError('Only tags should be ticked. '
+          'Attempted to tick: ${function.name}');
+    }
+    ++exclusiveTicks;
+    ++inclusiveTicks;
+    _normalizeTicks();
+  }
 }
 
 class SampleProfile extends M.SampleProfile {
@@ -757,35 +751,66 @@
   int sampleCount = 0;
   int samplePeriod = 0;
   double sampleRate = 0.0;
-
-  int stackDepth = 0;
+  int pid = 0;
+  int maxStackDepth = 0;
 
   double timeSpan = 0.0;
 
-  final Map<String, List> tries = <String, List>{};
-  final List<ProfileCode> codes = new List<ProfileCode>();
+  M.SampleProfileTag tagOrder = M.SampleProfileTag.none;
+
+  final _functionTagMapping = <String, int>{};
+  final _codeTagMapping = <String, int>{};
+
+  final List samples = [];
+  final codes = <ProfileCode>[];
   bool _builtCodeCalls = false;
-  final List<ProfileFunction> functions = new List<ProfileFunction>();
+  final functions = <ProfileFunction>[];
   bool _builtFunctionCalls = false;
 
+  static const String _kCode = 'code';
+  static const String _kCodes = '_codes';
+  static const String _kCodeStack = '_codeStack';
+  static const String _kFunction = 'function';
+  static const String _kFunctions = 'functions';
+  static const String _kNativeAllocationSizeBytes =
+      '_nativeAllocationSizeBytes';
+  static const String _kPid = 'pid';
+  static const String _kSampleCount = 'sampleCount';
+  static const String _kSamplePeriod = 'samplePeriod';
+  static const String _kSamples = 'samples';
+  static const String _kStack = 'stack';
+  static const String _kMaxStackDepth = 'maxStackDepth';
+  static const String _kTimeSpan = 'timespan';
+  static const String _kUserTag = 'userTag';
+  static const String _kVmTag = 'vmTag';
+
+  // Names of special tag types.
+  static const String kNativeTag = 'Native';
+  static const String kRootTag = 'Root';
+  static const String kRuntimeTag = 'Runtime';
+  static const String kTruncatedTag = '[Truncated]';
+
+  // Used to stash trie information in samples for timeline processing.
+  static const String kTimelineFunctionTrie = 'timelineFunctionTrie';
+
   CodeCallTree loadCodeTree(M.ProfileTreeDirection direction) {
     switch (direction) {
       case M.ProfileTreeDirection.inclusive:
-        return _loadCodeTree(true, tries['inclusiveCodeTrie']);
+        return _loadCodeTree(true);
       case M.ProfileTreeDirection.exclusive:
-        return _loadCodeTree(false, tries['exclusiveCodeTrie']);
+        return _loadCodeTree(false);
     }
-    throw new Exception('Unknown ProfileTreeDirection');
+    throw Exception('Unknown ProfileTreeDirection');
   }
 
   FunctionCallTree loadFunctionTree(M.ProfileTreeDirection direction) {
     switch (direction) {
       case M.ProfileTreeDirection.inclusive:
-        return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
+        return _loadFunctionTree(true);
       case M.ProfileTreeDirection.exclusive:
-        return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
+        return _loadFunctionTree(false);
     }
-    throw new Exception('Unknown ProfileTreeDirection');
+    throw Exception('Unknown ProfileTreeDirection');
   }
 
   buildCodeCallerAndCallees() {
@@ -807,14 +832,14 @@
   }
 
   clear() {
+    pid = -1;
     sampleCount = 0;
     samplePeriod = 0;
     sampleRate = 0.0;
-    stackDepth = 0;
+    maxStackDepth = 0;
     timeSpan = 0.0;
     codes.clear();
     functions.clear();
-    tries.clear();
     _builtCodeCalls = false;
     _builtFunctionCalls = false;
   }
@@ -823,268 +848,403 @@
     await loadProgress(owner, profile).drain();
   }
 
-  static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
-    final Completer completer = new Completer();
-    new Timer(duration, () => completer.complete());
-    return completer.future;
-  }
+  static Future sleep([Duration duration = const Duration(microseconds: 0)]) =>
+      Future.delayed(duration);
 
-  Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
-    Logger.root.info('sampling counters ${profile['counters']}');
-
-    var progress = new StreamController<double>.broadcast();
-
-    (() async {
-      final Stopwatch watch = new Stopwatch();
-      watch.start();
-      int count = 0;
-      var needToUpdate = () {
-        count++;
-        if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) {
-          watch.reset();
-          return true;
-        }
+  Future _loadCommon(ServiceObjectOwner owner, ServiceMap profile,
+      [StreamController<double> progress]) async {
+    final watch = Stopwatch();
+    watch.start();
+    int count = 0;
+    var needToUpdate = () {
+      if (progress == null) {
         return false;
-      };
-      var signal = (double p) {
-        progress.add(p);
-        return sleep();
-      };
-      try {
-        clear();
-        progress.add(0.0);
-        if (profile == null) {
-          return;
-        }
+      }
+      count++;
+      if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) {
+        watch.reset();
+        return true;
+      }
+      return false;
+    };
+    var signal = (double p) {
+      if (progress == null) {
+        return null;
+      }
+      progress.add(p);
+      return sleep();
+    };
+    try {
+      clear();
+      progress?.add(0.0);
+      if (profile == null) {
+        return;
+      }
 
-        if ((owner != null) && (owner is Isolate)) {
-          isolate = owner;
-          isolate.resetCachedProfileData();
-        }
+      if ((owner != null) && (owner is Isolate)) {
+        isolate = owner;
+        isolate.resetCachedProfileData();
+      }
 
-        sampleCount = profile['sampleCount'];
-        samplePeriod = profile['samplePeriod'];
-        sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
-        stackDepth = profile['stackDepth'];
-        timeSpan = profile['timeSpan'];
+      pid = profile[_kPid];
+      sampleCount = profile[_kSampleCount];
+      samplePeriod = profile[_kSamplePeriod];
+      sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
+      maxStackDepth = profile[_kMaxStackDepth];
+      timeSpan = profile[_kTimeSpan];
 
-        num length = profile['codes'].length + profile['functions'].length;
+      num length = 0;
 
-        // Process code table.
-        for (var codeRegion in profile['codes']) {
+      if (profile.containsKey(_kCodes)) {
+        length += profile[_kCodes].length;
+      }
+      length += profile[_kFunctions].length;
+
+      // Process code table.
+      int tableIndex = 0;
+      if (profile.containsKey(_kCodes)) {
+        for (var codeRegion in profile[_kCodes]) {
           if (needToUpdate()) {
             await signal(count * 100.0 / length);
           }
-          Code code = codeRegion['code'];
+          Code code = codeRegion[_kCode];
           assert(code != null);
-          codes.add(new ProfileCode.fromMap(this, code, codeRegion));
+          codes.add(ProfileCode.fromMap(tableIndex, this, code, codeRegion));
+          ++tableIndex;
         }
-        // Process function table.
-        for (var profileFunction in profile['functions']) {
-          if (needToUpdate()) {
-            await signal(count * 100 / length);
-          }
-          ServiceFunction function = profileFunction['function'];
-          assert(function != null);
-          functions.add(
-              new ProfileFunction.fromMap(this, function, profileFunction));
-        }
-
-        tries['exclusiveCodeTrie'] =
-            new Uint32List.fromList(profile['exclusiveCodeTrie'].cast<int>());
-        tries['inclusiveCodeTrie'] =
-            new Uint32List.fromList(profile['inclusiveCodeTrie'].cast<int>());
-        tries['exclusiveFunctionTrie'] = new Uint32List.fromList(
-            profile['exclusiveFunctionTrie'].cast<int>());
-        tries['inclusiveFunctionTrie'] = new Uint32List.fromList(
-            profile['inclusiveFunctionTrie'].cast<int>());
-      } finally {
-        progress.close();
       }
-    }());
+      // Process function table.
+      tableIndex = 0;
+      for (var profileFunction in profile[_kFunctions]) {
+        if (needToUpdate()) {
+          await signal(count * 100 / length);
+        }
+        ServiceFunction function = profileFunction[_kFunction];
+        assert(function != null);
+        functions.add(ProfileFunction.fromMap(
+            tableIndex, this, function, profileFunction));
+        ++tableIndex;
+      }
+      if (profile.containsKey(_kCodes)) {
+        _buildCodeTagMapping();
+      }
+
+      _buildFunctionTagMapping();
+
+      samples.addAll(profile[_kSamples]);
+    } finally {
+      progress?.close();
+    }
+  }
+
+  Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
+    Logger.root.info('sampling counters ${profile['_counters']}');
+
+    var progress = StreamController<double>.broadcast();
+
+    _loadCommon(owner, profile, progress);
     return progress.stream;
   }
 
-  // Data shared across calls to _read*TrieNode.
-  int _dataCursor = 0;
+  // Helpers for reading optional flags from a sample.
+  static bool _isNativeEntryTag(Map sample) =>
+      sample.containsKey('nativeEntryTag');
+  static bool _isRuntimeEntryTag(Map sample) =>
+      sample.containsKey('runtimeEntryTag');
+  static bool _isTruncated(Map sample) => sample.containsKey('truncated');
+  static bool _isNativeAllocationSample(Map sample) =>
+      sample.containsKey('_nativeAllocationSizeBytes');
 
-  // The code trie is serialized as a list of integers. Each node
-  // is recreated by consuming some portion of the list. The format is as
-  // follows:
-  // [0] index into codeTable of code object.
-  // [1] tick count (number of times this stack frame occured).
-  // [2] child node count
-  // Reading the trie is done by recursively reading the tree depth-first
-  // pre-order.
-  CodeCallTree _loadCodeTree(bool inclusive, List<int> data) {
-    if (data == null) {
-      return null;
+  int _getProfileFunctionTagIndex(String tag) {
+    if (_functionTagMapping.containsKey(tag)) {
+      return _functionTagMapping[tag];
     }
-    if (data.length < 3) {
-      // Not enough for root node.
-      return null;
-    }
-    // Read the tree, returns the root node.
-    var root = _readCodeTrie(data);
-    return new CodeCallTree(inclusive, root);
+    throw ArgumentError('$tag is not a valid tag!');
   }
 
-  CodeCallTreeNode _readCodeTrieNode(List<int> data) {
-    // Lookup code object.
-    var codeIndex = data[_dataCursor++];
-    var code = codes[codeIndex];
-    // Node tick counter.
-    var count = data[_dataCursor++];
-    // Child node count.
-    var children = data[_dataCursor++];
-    // Inclusive native allocations.
-    var inclusiveNativeAllocations = data[_dataCursor++];
-    // Exclusive native allocations.
-    var exclusiveNativeAllocations = data[_dataCursor++];
-    // Create node.
-    var node = new CodeCallTreeNode(
-        code, count, inclusiveNativeAllocations, exclusiveNativeAllocations);
-    node.children.length = children;
-    return node;
+  int _getProfileCodeTagIndex(String tag) {
+    if (_codeTagMapping.containsKey(tag)) {
+      return _codeTagMapping[tag];
+    }
+    throw ArgumentError('$tag is not a valid tag!');
   }
 
-  CodeCallTreeNode _readCodeTrie(List<int> data) {
-    final nodeStack = new List<CodeCallTreeNode>();
-    final childIndexStack = new List<int>();
+  void _buildFunctionTagMapping() {
+    for (int i = 0; i < functions.length; ++i) {
+      final function = functions[i].function;
+      if (function.kind == M.FunctionKind.tag) {
+        _functionTagMapping[function.name] = i;
+      }
+    }
+  }
 
-    _dataCursor = 0;
-    // Read root.
-    var root = _readCodeTrieNode(data);
+  void _buildCodeTagMapping() {
+    for (int i = 0; i < codes.length; ++i) {
+      final code = codes[i].code;
+      if (code.kind == M.CodeKind.tag) {
+        _codeTagMapping[code.name] = i;
+      }
+    }
+  }
 
-    // Push root onto stack.
-    if (root.children.length > 0) {
-      nodeStack.add(root);
-      childIndexStack.add(0);
+  void _clearProfileFunctionTagTicks() =>
+      _functionTagMapping.forEach((String name, int tableIndex) {
+        // Truncated tag is ticked in the VM, so don't clear it.
+        if (name != kTruncatedTag) {
+          functions[tableIndex].clearTicks();
+        }
+      });
+
+  void _clearProfileCodeTagTicks() =>
+      _codeTagMapping.forEach((String name, int tableIndex) {
+        // Truncated tag is ticked in the VM, so don't clear it.
+        if (name != kTruncatedTag) {
+          codes[tableIndex].clearTicks();
+        }
+      });
+
+  NodeT _appendUserTag<NodeT extends CallTreeNode>(
+      String userTag, NodeT current, Map sample) {
+    bool isCode = (current is CodeCallTreeNode);
+    try {
+      final tableIndex = isCode
+          ? _getProfileCodeTagIndex(userTag)
+          : _getProfileFunctionTagIndex(userTag);
+      current = current.getChild(tableIndex);
+      current.tick(sample);
+    } catch (_) {/* invalid tag */} finally {
+      return current;
+    }
+  }
+
+  NodeT _appendTruncatedTag<NodeT extends CallTreeNode>(
+      NodeT current, Map sample) {
+    final isCode = (current is CodeCallTreeNode);
+    try {
+      final tableIndex = isCode
+          ? _getProfileCodeTagIndex(kTruncatedTag)
+          : _getProfileFunctionTagIndex(kTruncatedTag);
+      current = current.getChild(tableIndex);
+      current.tick(sample);
+      // We don't need to tick the tag itself since this is done in the VM for
+      // the truncated tag, unlike other VM and user tags.
+    } catch (_) {/* invalid tag */} finally {
+      return current;
+    }
+  }
+
+  FunctionCallTreeNode _getFunctionTagAndTick(
+      String tag, FunctionCallTreeNode current, Map sample) {
+    try {
+      final tableIndex = _getProfileFunctionTagIndex(tag);
+      current = current.getChild(tableIndex);
+      current.tick(sample);
+    } catch (_) {/* invalid tag */} finally {
+      return current;
+    }
+  }
+
+  CodeCallTreeNode _getCodeTagAndTick(
+      String tag, CodeCallTreeNode current, Map sample) {
+    try {
+      final tableIndex = _getProfileCodeTagIndex(tag);
+      current = current.getChild(tableIndex);
+      current.tick(sample);
+    } catch (_) {/* invalid tag */} finally {
+      return current;
+    }
+  }
+
+  NodeT _getTagAndTick<NodeT extends CallTreeNode>(
+      String tag, NodeT current, Map sample) {
+    if (current is FunctionCallTreeNode) {
+      return _getFunctionTagAndTick(tag, current, sample) as NodeT;
+    } else if (current is CodeCallTreeNode) {
+      return _getCodeTagAndTick(tag, current, sample) as NodeT;
+    }
+    throw ArgumentError('Unexpected tree type: $NodeT');
+  }
+
+  NodeT _appendVMTag<NodeT extends CallTreeNode>(
+      String vmTag, NodeT current, Map sample) {
+    if (_isNativeEntryTag(sample)) {
+      return _getTagAndTick(kNativeTag, current, sample);
+    } else if (_isRuntimeEntryTag(sample)) {
+      return _getTagAndTick(kRuntimeTag, current, sample);
+    } else {
+      return _getTagAndTick(vmTag, current, sample);
+    }
+  }
+
+  NodeT _appendSpecificNativeRuntimeEntryVMTag<NodeT extends CallTreeNode>(
+      NodeT current, Map sample) {
+    // Only Native and Runtime entries have a second VM tag.
+    if (!_isNativeEntryTag(sample) && !_isRuntimeEntryTag(sample)) {
+      return current;
+    }
+    final vmTag = sample[_kVmTag];
+    return _getTagAndTick(vmTag, current, sample);
+  }
+
+  NodeT _appendVMTags<NodeT extends CallTreeNode>(
+      String vmTag, NodeT current, Map sample) {
+    current = _appendVMTag(vmTag, current, sample);
+    current = _appendSpecificNativeRuntimeEntryVMTag(current, sample);
+    return current;
+  }
+
+  void _tickTags(String vmTag, String userTag, bool tickCode) {
+    if (tickCode) {
+      final vmTagIndex = _getProfileCodeTagIndex(vmTag);
+      codes[vmTagIndex].tickTag();
+
+      final userTagIndex = _getProfileCodeTagIndex(userTag);
+      codes[userTagIndex].tickTag();
+    } else {
+      final vmTagIndex = _getProfileFunctionTagIndex(vmTag);
+      functions[vmTagIndex].tickTag();
+
+      final userTagIndex = _getProfileFunctionTagIndex(userTag);
+      functions[userTagIndex].tickTag();
+    }
+  }
+
+  NodeT _appendTags<NodeT extends CallTreeNode>(
+      String vmTag, String userTag, NodeT current, Map sample) {
+    final tickCode = (current is M.CodeCallTreeNode);
+    _tickTags(vmTag, userTag, tickCode);
+    if (tagOrder == M.SampleProfileTag.none) {
+      return current;
+    }
+    // User first.
+    if (tagOrder == M.SampleProfileTag.userVM ||
+        tagOrder == M.SampleProfileTag.userOnly) {
+      current = _appendUserTag(userTag, current, sample);
+      // Only user.
+      if (tagOrder == M.SampleProfileTag.userOnly) {
+        return current;
+      }
+      return _appendVMTags(vmTag, current, sample);
     }
 
-    while (nodeStack.length > 0) {
-      var lastIndex = nodeStack.length - 1;
-      // Pop parent from stack.
-      var parent = nodeStack[lastIndex];
-      var childIndex = childIndexStack[lastIndex];
+    // VM first.
+    current = _appendVMTags(vmTag, current, sample);
+    // Only VM.
+    if (tagOrder == M.SampleProfileTag.vmOnly) {
+      return current;
+    }
+    return _appendUserTag(userTag, current, sample);
+  }
 
-      // Read child node.
-      assert(childIndex < parent.children.length);
-      var node = _readCodeTrieNode(data);
-      parent.children[childIndex++] = node;
+  NodeT _processFrame<NodeT extends CallTreeNode>(NodeT parent, int sampleIndex,
+      Map sample, List<int> stack, int frameIndex, bool inclusive) {
+    final child = parent.getChild(stack[frameIndex]);
+    child.tick(sample, exclusive: (frameIndex == 0));
+    return child;
+  }
 
-      // If parent still has children, update child index.
-      if (childIndex < parent.children.length) {
-        childIndexStack[lastIndex] = childIndex;
+  FunctionCallTreeNode buildFunctionTrie(bool inclusive) {
+    final root = FunctionCallTreeNode.fromIndex(
+        this, _getProfileFunctionTagIndex(kRootTag));
+
+    for (int sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) {
+      final sample = samples[sampleIndex];
+      FunctionCallTreeNode current = root;
+      // Tick the root for each sample as we always visit the root node.
+      root.tick(sample);
+
+      // VM + User tags.
+      final vmTag = sample[_kVmTag];
+      final userTag = sample[_kUserTag];
+      final stack = sample[_kStack].cast<int>();
+      current = _appendTags(vmTag, userTag, current, sample);
+
+      if (inclusive) {
+        if (_isTruncated(sample)) {
+          current = _appendTruncatedTag(current, sample);
+        }
+        for (int frameIndex = stack.length - 1; frameIndex >= 0; --frameIndex) {
+          current = _processFrame(
+              current, sampleIndex, sample, stack, frameIndex, true);
+        }
+
+        // Used by the timeline to find the root of each sample.
+        sample[kTimelineFunctionTrie] = current;
       } else {
-        // Finished processing parent node.
-        nodeStack.removeLast();
-        childIndexStack.removeLast();
-      }
+        for (int frameIndex = 0; frameIndex < stack.length; ++frameIndex) {
+          current = _processFrame(
+              current, sampleIndex, sample, stack, frameIndex, false);
+        }
 
-      // If node has children, push onto stack.
-      if (node.children.length > 0) {
-        nodeStack.add(node);
-        childIndexStack.add(0);
+        if (_isTruncated(sample)) {
+          current = _appendTruncatedTag(current, sample);
+        }
       }
     }
-
     return root;
   }
 
-  FunctionCallTree _loadFunctionTree(bool inclusive, List<int> data) {
-    if (data == null) {
-      return null;
-    }
-    if (data.length < 3) {
-      // Not enough integers for 1 node.
-      return null;
-    }
-    // Read the tree, returns the root node.
-    var root = _readFunctionTrie(data);
-    return new FunctionCallTree(inclusive, root);
-  }
+  CodeCallTreeNode buildCodeTrie(bool inclusive) {
+    final root =
+        CodeCallTreeNode.fromIndex(this, _getProfileCodeTagIndex(kRootTag));
 
-  FunctionCallTreeNode _readFunctionTrieNode(List<int> data) {
-    // Read index into function table.
-    var index = data[_dataCursor++];
-    // Lookup function object.
-    var function = functions[index];
-    // Counter.
-    var count = data[_dataCursor++];
-    // Inclusive native allocations.
-    var inclusiveNativeAllocations = data[_dataCursor++];
-    // Exclusive native allocations.
-    var exclusiveNativeAllocations = data[_dataCursor++];
-    // Create node.
-    var node = new FunctionCallTreeNode(function, count,
-        inclusiveNativeAllocations, exclusiveNativeAllocations);
-    // Number of code index / count pairs.
-    var codeCount = data[_dataCursor++];
-    node.codes.length = codeCount;
-    var totalCodeTicks = 0;
-    for (var i = 0; i < codeCount; i++) {
-      var codeIndex = data[_dataCursor++];
-      var code = codes[codeIndex];
-      assert(code != null);
-      var codeTicks = data[_dataCursor++];
-      totalCodeTicks += codeTicks;
-      var nodeCode = new FunctionCallTreeNodeCode(code, codeTicks);
-      node.codes[i] = nodeCode;
-    }
-    node.setCodeAttributes();
-    node._totalCodeTicks = totalCodeTicks;
-    // Number of children.
-    var childCount = data[_dataCursor++];
-    node.children.length = childCount;
-    return node;
-  }
+    for (int sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) {
+      final sample = samples[sampleIndex];
 
-  FunctionCallTreeNode _readFunctionTrie(List<int> data) {
-    final nodeStack = new List<FunctionCallTreeNode>();
-    final childIndexStack = new List<int>();
+      CodeCallTreeNode current = root;
+      // Tick the root for each sample as we always visit the root node.
+      root.tick(sample);
 
-    _dataCursor = 0;
+      // VM + User tags.
+      final vmTag = sample[_kVmTag];
+      final userTag = sample[_kUserTag];
+      final stack = sample[_kCodeStack].cast<int>();
+      current = _appendTags(vmTag, userTag, current, sample);
 
-    // Read root.
-    var root = _readFunctionTrieNode(data);
-
-    // Push root onto stack.
-    if (root.children.length > 0) {
-      nodeStack.add(root);
-      childIndexStack.add(0);
-    }
-
-    while (nodeStack.length > 0) {
-      var lastIndex = nodeStack.length - 1;
-      // Pop parent from stack.
-      var parent = nodeStack[lastIndex];
-      var childIndex = childIndexStack[lastIndex];
-
-      // Read child node.
-      assert(childIndex < parent.children.length);
-      var node = _readFunctionTrieNode(data);
-      parent.children[childIndex++] = node;
-
-      // If parent still has children, update child index.
-      if (childIndex < parent.children.length) {
-        childIndexStack[lastIndex] = childIndex;
+      if (inclusive) {
+        if (_isTruncated(sample)) {
+          current = _appendTruncatedTag(current, sample);
+        }
+        for (int frameIndex = stack.length - 1; frameIndex >= 0; --frameIndex) {
+          current = _processFrame(
+              current, sampleIndex, sample, stack, frameIndex, true);
+        }
       } else {
-        // Finished processing parent node.
-        nodeStack.removeLast();
-        childIndexStack.removeLast();
-      }
+        for (int frameIndex = 0; frameIndex < stack.length; ++frameIndex) {
+          current = _processFrame(
+              current, sampleIndex, sample, stack, frameIndex, false);
+        }
 
-      // If node has children, push onto stack.
-      if (node.children.length > 0) {
-        nodeStack.add(node);
-        childIndexStack.add(0);
+        if (_isTruncated(sample)) {
+          current = _appendTruncatedTag(current, sample);
+        }
       }
     }
-
     return root;
   }
 
+  FunctionCallTree _loadFunctionTree(bool inclusive) {
+    // Since we're only ticking tag functions when building the trie, we need
+    // to clean up ticks from previous tree builds.
+    _clearProfileFunctionTagTicks();
+
+    // Read the tree, returns the root node.
+    final root = buildFunctionTrie(inclusive);
+    root.sortChildren();
+    return FunctionCallTree(inclusive, root);
+  }
+
+  CodeCallTree _loadCodeTree(bool inclusive) {
+    // Since we're only ticking tag code when building the trie, we need
+    // to clean up ticks from previous tree builds.
+    _clearProfileCodeTagTicks();
+
+    // Read the tree, returns the root node.
+    final root = buildCodeTrie(inclusive);
+    root.sortChildren();
+    return CodeCallTree(inclusive, root);
+  }
+
   int approximateMillisecondsForCount(count) {
     return (count * samplePeriod) ~/ Duration.microsecondsPerMillisecond;
   }
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 866aed5..afbb7cc 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -220,6 +220,7 @@
         obj = new Frame._empty(owner);
         break;
       case 'Function':
+      case 'NativeFunction':
         obj = new ServiceFunction._empty(owner);
         break;
       case 'Gauge':
@@ -693,7 +694,7 @@
     updateFromServiceMap({'name': 'vm', 'type': '@VM'});
   }
 
-  void postServiceEvent(String streamId, Map response, ByteData data) {
+  void postServiceEvent(String streamId, Map response, Uint8List data) {
     var map = response;
     assert(!map.containsKey('_data'));
     if (data != null) {
@@ -1329,10 +1330,6 @@
     }
   }
 
-  Future collectAllGarbage() {
-    return invokeRpc('_collectAllGarbage', {});
-  }
-
   /// Fetches and builds the class hierarchy for this isolate. Returns the
   /// Object class object.
   Future<Class> getClassHierarchy() async {
@@ -1461,7 +1458,7 @@
   DartError error;
   StreamController _snapshotFetch;
 
-  List<ByteData> _chunksInProgress;
+  List<Uint8List> _chunksInProgress;
 
   List<Thread> get threads => _threads;
   final List<Thread> _threads = new List<Thread>();
@@ -1475,6 +1472,20 @@
   int get numScopedHandles => _numScopedHandles;
   int _numScopedHandles;
 
+  static Uint8List _flatten(List<Uint8List> chunks) {
+    var length = 0;
+    for (var chunk in chunks) {
+      length += chunk.length;
+    }
+    var flattened = new Uint8List(length);
+    var position = 0;
+    for (var chunk in chunks) {
+      flattened.setRange(position, position + chunk.length, chunk);
+      position += chunk.length;
+    }
+    return flattened;
+  }
+
   void _loadHeapSnapshot(ServiceEvent event) {
     if (_snapshotFetch == null || _snapshotFetch.isClosed) {
       // No outstanding snapshot request. Presumably another client asked for a
@@ -1494,11 +1505,11 @@
       return;
     }
 
-    var loadedChunks = _chunksInProgress;
-    _chunksInProgress = null;
+    var flattened = _flatten(_chunksInProgress);
+    _chunksInProgress = null; // Make chunks GC'able.
 
     if (_snapshotFetch != null) {
-      _snapshotFetch.add(loadedChunks);
+      _snapshotFetch.add(flattened);
       _snapshotFetch.close();
     }
   }
@@ -2091,7 +2102,7 @@
   DartError reloadError;
   bool atAsyncSuspension;
   Instance inspectee;
-  ByteData data;
+  Uint8List data;
   int count;
   String reason;
   String exceptions;
@@ -2558,8 +2569,10 @@
     });
   }
 
-  Future<ServiceObject> getAllocationSamples([String tags = 'None']) {
-    var params = {'tags': tags, 'classId': id};
+  Future<ServiceObject> getAllocationSamples() {
+    var params = {
+      'classId': id,
+    };
     return isolate.invokeRpc('_getAllocationSamples', params);
   }
 
diff --git a/runtime/observatory/observatory_sources.gni b/runtime/observatory/observatory_sources.gni
index c69b433..1cd8af3 100644
--- a/runtime/observatory/observatory_sources.gni
+++ b/runtime/observatory/observatory_sources.gni
@@ -134,6 +134,7 @@
   "lib/src/elements/subtypetestcache_view.dart",
   "lib/src/elements/timeline/dashboard.dart",
   "lib/src/elements/timeline_page.dart",
+  "lib/src/elements/tree_map.dart",
   "lib/src/elements/type_arguments_ref.dart",
   "lib/src/elements/unknown_ref.dart",
   "lib/src/elements/unlinkedcall_ref.dart",
diff --git a/runtime/observatory/pubspec.yaml b/runtime/observatory/pubspec.yaml
index 2059c3d..8c4c378 100644
--- a/runtime/observatory/pubspec.yaml
+++ b/runtime/observatory/pubspec.yaml
@@ -1,3 +1,3 @@
 name: observatory
 environment:
-  sdk: '>=2.2.0 <3.0.0'
+  sdk: '>=2.2.2 <3.0.0'
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/collect_all_garbage_test.dart b/runtime/observatory/tests/service/collect_all_garbage_test.dart
deleted file mode 100644
index 8db2921..0000000
--- a/runtime/observatory/tests/service/collect_all_garbage_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-
-import 'test_helper.dart';
-
-var tests = <IsolateTest>[
-  (Isolate isolate) async {
-    var result = await isolate.invokeRpcNoUpgrade('_collectAllGarbage', {});
-    expect(result['type'], equals('Success'));
-  },
-];
-
-main(args) async => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/echo_test.dart b/runtime/observatory/tests/service/echo_test.dart
index fdd93cf..eda2f81 100644
--- a/runtime/observatory/tests/service/echo_test.dart
+++ b/runtime/observatory/tests/service/echo_test.dart
@@ -25,9 +25,9 @@
     subscription = stream.listen((ServiceEvent event) {
       assert(event.kind == '_Echo');
       expect(event.data.lengthInBytes, equals(3));
-      expect(event.data.getUint8(0), equals(0));
-      expect(event.data.getUint8(1), equals(128));
-      expect(event.data.getUint8(2), equals(255));
+      expect(event.data[0], equals(0));
+      expect(event.data[1], equals(128));
+      expect(event.data[2], equals(255));
       subscription.cancel();
       completer.complete();
     });
diff --git a/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
index 537a69d..a0d7f9e 100644
--- a/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:observatory/src/repositories/timeline_base.dart';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 
@@ -19,13 +20,8 @@
   print("Testee did something.");
 }
 
-Future checkTimeline(Isolate isolate, Map params) async {
-  print(params);
-  var result =
-      await isolate.invokeRpcNoUpgrade('_getCpuProfileTimeline', params);
-  print(result);
-  expect(result['type'], equals('_CpuProfileTimeline'));
-
+Future checkTimeline(VM vm) async {
+  var result = await TimelineRepositoryBase().getCpuProfileTimeline(vm);
   var isString = new isInstanceOf<String>();
   var isInt = new isInstanceOf<int>();
   Map frames = result['stackFrames'];
@@ -53,24 +49,14 @@
   }
 }
 
-var tests = <IsolateTest>[
-  (Isolate i) => checkTimeline(i, {'tags': 'VMUser'}),
-  (Isolate i) => checkTimeline(i, {'tags': 'VMUser', 'code': true}),
-  (Isolate i) => checkTimeline(i, {'tags': 'VMUser', 'code': false}),
-  (Isolate i) => checkTimeline(i, {'tags': 'VMOnly'}),
-  (Isolate i) => checkTimeline(i, {'tags': 'VMOnly', 'code': true}),
-  (Isolate i) => checkTimeline(i, {'tags': 'VMOnly', 'code': false}),
-  (Isolate i) => checkTimeline(i, {'tags': 'None'}),
-  (Isolate i) => checkTimeline(i, {'tags': 'None', 'code': true}),
-  (Isolate i) => checkTimeline(i, {'tags': 'None', 'code': false}),
+var tests = <VMTest>[
+  (VM vm) => checkTimeline(vm),
 ];
 
 var vmArgs = [
   '--profiler=true',
   '--profile-vm=false', // So this also works with DBC and KBC.
-  '--timeline_recorder=ring',
-  '--timeline_streams=Profiler'
 ];
 
 main(args) async =>
-    runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
+    runVMTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart b/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart
new file mode 100644
index 0000000..aa55eb3
--- /dev/null
+++ b/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+fib(n) {
+  if (n < 0) return 0;
+  if (n == 0) return 1;
+  return fib(n - 1) + fib(n - 2);
+}
+
+testeeDo() {
+  print("Testee doing something.");
+  fib(30);
+  print("Testee did something.");
+}
+
+Future checkSamples(Isolate isolate) async {
+  final result =
+      await isolate.invokeRpcNoUpgrade('getCpuSamples', {'_code': true});
+  expect(result['type'], equals('CpuSamples'));
+
+  final isString = isInstanceOf<String>();
+  final isInt = isInstanceOf<int>();
+  final isList = isInstanceOf<List>();
+  final functions = result['functions'];
+  expect(functions.length, greaterThan(10),
+      reason: "Should have many functions");
+  final codes = result['_codes'];
+  expect(functions.length, greaterThan(10),
+      reason: "Should have many code objects");
+
+  final samples = result['samples'];
+  expect(samples.length, greaterThan(10), reason: "Should have many samples");
+  final sample = samples.first;
+  expect(sample['tid'], isInt);
+  expect(sample['timestamp'], isInt);
+  if (sample.containsKey('vmTag')) {
+    expect(sample['vmTag'], isString);
+  }
+  if (sample.containsKey('userTag')) {
+    expect(sample['userTag'], isString);
+  }
+  expect(sample['stack'], isList);
+  expect(sample['_codeStack'], isList);
+}
+
+var tests = <IsolateTest>[
+  (Isolate i) => checkSamples(i),
+];
+
+var vmArgs = [
+  '--profiler=true',
+  '--profile-vm=false', // So this also works with DBC and KBC.
+];
+
+main(args) async =>
+    runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/tests/service/get_native_allocation_samples_test.dart b/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
index 97535e5..7ade11d 100644
--- a/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
@@ -15,12 +15,12 @@
     return;
   }
 
-/*  if (!(root is FunctionCallTreeNode)) {
+  if (!(root is FunctionCallTreeNode)) {
     print('${root.profileCode.code.name}');
   } else {
     print('${root.profileFunction.function.name}');
   }
-*/
+
   int inclusiveAllocations = 0;
   int exclusiveAllocations = 0;
 
@@ -57,7 +57,7 @@
   // Verify inclusive tries.
   (VM vm) async {
     var response =
-        await vm.invokeRpc('_getNativeAllocationSamples', {'tags': 'None'});
+        await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
     SampleProfile cpuProfile = new SampleProfile();
     await cpuProfile.load(vm, response);
     var codeTree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.inclusive);
@@ -69,7 +69,7 @@
   // Verify exclusive tries.
   (VM vm) async {
     var response =
-        await vm.invokeRpc('_getNativeAllocationSamples', {'tags': 'None'});
+        await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
     SampleProfile cpuProfile = new SampleProfile();
     await cpuProfile.load(vm, response);
     var codeTreeExclusive =
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 0a1fa50..f062d33 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
     var result = await vm.invokeRpcNoUpgrade('getVersion', {});
     expect(result['type'], equals('Version'));
     expect(result['major'], equals(3));
-    expect(result['minor'], equals(26));
+    expect(result['minor'], equals(27));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
index f683ab7..637790f 100644
--- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
@@ -14,9 +14,10 @@
   Timeline.instantSync('ISYNC', arguments: {'fruit': 'banana'});
   Timeline.finishSync();
   TimelineTask task = new TimelineTask();
-  task.start('TASK1');
-  task.instant('ITASK');
-  task.finish();
+  task.start('TASK1', arguments: {'task1-start-key': 'task1-start-value'});
+  task.instant('ITASK',
+      arguments: {'task1-instant-key': 'task1-instant-value'});
+  task.finish(arguments: {'task1-finish-key': 'task1-finish-value'});
 
   Flow flow = Flow.begin(id: 123);
   Timeline.startSync('peach', flow: flow);
@@ -31,10 +32,23 @@
   return events.where((event) => event['cat'] == 'Dart').toList();
 }
 
-bool eventsContains(List events, String phase, String name) {
+bool mapContains(Map map, Map submap) {
+  for (var key in submap.keys) {
+    if (map[key] != submap[key]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool eventsContains(List events, String phase, String name, [Map arguments]) {
   for (Map event in events) {
     if ((event['ph'] == phase) && (event['name'] == name)) {
-      return true;
+      if (arguments == null) {
+        return true;
+      } else if (mapContains(event['args'], arguments)) {
+        return true;
+      }
     }
   }
   return false;
@@ -108,11 +122,21 @@
     expect(dartEvents.length, equals(11));
     allEventsHaveIsolateNumber(dartEvents);
     allEventsHaveIsolateNumber(result['traceEvents']);
-    expect(eventsContains(dartEvents, 'i', 'ISYNC'), isTrue);
+    expect(
+        eventsContains(dartEvents, 'i', 'ISYNC', {'fruit': 'banana'}), isTrue);
     expect(eventsContains(dartEvents, 'X', 'apple'), isTrue);
-    expect(eventsContains(dartEvents, 'b', 'TASK1'), isTrue);
-    expect(eventsContains(dartEvents, 'e', 'TASK1'), isTrue);
-    expect(eventsContains(dartEvents, 'n', 'ITASK'), isTrue);
+    expect(
+        eventsContains(
+            dartEvents, 'b', 'TASK1', {'task1-start-key': 'task1-start-value'}),
+        isTrue);
+    expect(
+        eventsContains(dartEvents, 'e', 'TASK1',
+            {'task1-finish-key': 'task1-finish-value'}),
+        isTrue);
+    expect(
+        eventsContains(dartEvents, 'n', 'ITASK',
+            {'task1-instant-key': 'task1-instant-value'}),
+        isTrue);
     expect(eventsContains(dartEvents, 'q', 'ITASK'), isFalse);
     expect(eventsContains(dartEvents, 'X', 'peach'), isTrue);
     expect(eventsContains(dartEvents, 'X', 'watermelon'), isTrue);
diff --git a/runtime/observatory/tests/service/regress_28443_test.dart b/runtime/observatory/tests/service/regress_28443_test.dart
index 3590e51..bd585b9 100644
--- a/runtime/observatory/tests/service/regress_28443_test.dart
+++ b/runtime/observatory/tests/service/regress_28443_test.dart
@@ -38,28 +38,6 @@
   }
 }
 
-Future stepThroughProgram(Isolate isolate) async {
-  Completer completer = new Completer();
-  int pauseEventsSeen = 0;
-
-  await subscribeToStream(isolate.vm, VM.kDebugStream,
-      (ServiceEvent event) async {
-    if (event.kind == ServiceEvent.kPauseBreakpoint) {
-      // We are paused: Step further.
-      pauseEventsSeen++;
-      isolate.stepInto();
-    } else if (event.kind == ServiceEvent.kPauseExit) {
-      // We are at the exit: The test is done.
-      expect(pauseEventsSeen > 20, true,
-          reason: "Saw only $pauseEventsSeen pause events.");
-      await cancelStreamSubscription(VM.kDebugStream);
-      completer.complete();
-    }
-  });
-  isolate.resume();
-  return completer.future;
-}
-
 var tests = <IsolateTest>[
   hasPausedAtStart,
   markDartColonLibrariesDebuggable,
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 7550118..0cdbc33 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -47,12 +47,6 @@
 [ $mode == debug && ($arch == simarm || $arch == simarm64) ]
 *: SkipSlow
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
-[ !$strong && ($compiler == dartk || $compiler == dartkp) ]
-*: Skip
-
 # These tests are slow on simulators.
 [ $arch == simarm || $arch == simarm64 ]
 *: Pass, Slow
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 8ac0c0f..3c70570 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -37,22 +37,6 @@
 simple_reload_test: RuntimeError, Timeout # Issue 35506
 unused_changes_in_last_reload_test: RuntimeError
 
-# Kernel works slightly different. There are kernel specific versions.
-# These are the non-kernel specific versions so skip tests and allow errors.
-[ $compiler == dartk ]
-add_breakpoint_rpc_test: SkipByDesign # non-kernel specific version of add_breakpoint_rpc_kernel_test.
-bad_reload_test: RuntimeError # Issue 34025
-coverage_optimized_function_test: Pass, Slow
-evaluate_activation_in_method_class_test: RuntimeError # Issue 35505
-evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
-evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
-get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
-pause_on_unhandled_async_exceptions2_test: Pass, Slow
-unused_changes_in_last_reload_test: RuntimeError
-
-[ $compiler == dartkb ]
-*: Skip # Debugging capabilities are not yet supported in bytecode modes.
-
 [ $compiler == dartkp ]
 *: SkipByDesign # Non-kernel also skips precompiled mode.
 
@@ -81,12 +65,15 @@
 [ $arch == simdbc64 && $compiler == dartk && $mode == debug ]
 eval_test: Pass, Slow
 
-[ $compiler == dartk && $mode == debug ]
+[ $compiler == dartkb && ($builder_tag == bytecode_interpreter || $builder_tag == bytecode_mixed) ]
+*: Skip # There are still timeouts in the interpreter and mixed modes which cause infra timeouts.
+
+[ $mode == debug && ($compiler == dartk || $compiler == dartkb) ]
 isolate_lifecycle_test: Skip # Flaky.
 pause_idle_isolate_test: Skip # Flaky
 rewind_optimized_out_test: Pass, Slow
 
-[ $compiler == dartk && $system == windows ]
+[ $system == windows && ($compiler == dartk || $compiler == dartkb) ]
 add_breakpoint_rpc_kernel_test: Skip # Timeout
 break_on_default_constructor_test: Skip # Issues 32137 and 32138.
 breakpoint_in_parts_class_test: Skip # Timeout
@@ -137,7 +124,7 @@
 step_through_switch_test: Skip # Times out. Issue 32137.
 step_through_switch_with_continue_test: Skip # Times out. Issue 32137.
 
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simdbc64) ]
+[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
 add_breakpoint_rpc_kernel_test: RuntimeError # Issue #34736
 async_generator_breakpoint_test: SkipByDesign # No incremental compiler available.
 bad_reload_test: Skip # Times out on sim architectures, also RuntimeError.
@@ -172,3 +159,16 @@
 simple_reload_test: RuntimeError, Timeout
 unused_changes_in_last_reload_test: Skip # Times out on sim architectures.
 valid_source_locations_test: Pass, Slow, Timeout # Issue 34736
+
+# Kernel works slightly different. There are kernel specific versions.
+# These are the non-kernel specific versions so skip tests and allow errors.
+[ $compiler == dartk || $compiler == dartkb ]
+add_breakpoint_rpc_test: SkipByDesign # non-kernel specific version of add_breakpoint_rpc_kernel_test.
+bad_reload_test: RuntimeError # Issue 34025
+coverage_optimized_function_test: Pass, Slow
+evaluate_activation_in_method_class_test: RuntimeError # Issue 35505
+evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
+evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
+get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
+pause_on_unhandled_async_exceptions2_test: Pass, Slow
+unused_changes_in_last_reload_test: RuntimeError
diff --git a/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart b/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart
deleted file mode 100644
index fad0eda..0000000
--- a/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-
-import 'test_helper.dart';
-
-fib(n) {
-  if (n < 0) return 0;
-  if (n == 0) return 1;
-  return fib(n - 1) + fib(n - 2);
-}
-
-testeeDo() {
-  print("Testee doing something.");
-  fib(30);
-  print("Testee did something.");
-}
-
-var tests = <IsolateTest>[
-  (Isolate isolate) async {
-    var params = {'tags': 'None'};
-    var result =
-        await isolate.invokeRpcNoUpgrade('_writeCpuProfileTimeline', params);
-    print(result);
-    expect(result['type'], equals('Success'));
-
-    result = await isolate.vm.invokeRpcNoUpgrade('getVMTimeline', {});
-    expect(result['type'], equals('Timeline'));
-    expect(result['traceEvents'], new isInstanceOf<List>());
-
-    var events = result['traceEvents'];
-    print(events);
-    var profilerSampleEvents = result['traceEvents'].where((event) {
-      return event['name'] == "Dart CPU sample";
-    }).toList();
-
-    var isString = new isInstanceOf<String>();
-    var isInt = new isInstanceOf<int>();
-
-    expect(profilerSampleEvents.length, greaterThan(10),
-        reason: "Should have many samples");
-    for (Map event in profilerSampleEvents) {
-      print(event);
-
-      // Sadly this is an "Instant" event because there is no way to add a
-      // proper "Sample" event in Fuchsia's tracing.
-      expect(event['ph'], equals('i'));
-
-      expect(event['pid'], isInt);
-      expect(event['tid'], isInt);
-      expect(event['ts'], isInt);
-      expect(event['cat'], equals("Profiler"));
-      expect(event['args']['backtrace'], isString);
-    }
-  },
-];
-
-var vmArgs = [
-  '--profiler=true',
-  '--profile-vm=false', // So this also works with DBC and KBC.
-  '--timeline_recorder=ring',
-  '--timeline_streams=Profiler'
-];
-
-main(args) async =>
-    runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index 8ed70cb..56afbbbe 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -4,7 +4,6 @@
 
 // See also timeline_message_handler.js.
 
-var traceObject;
 var pendingRequests;
 var loadingOverlay;
 
@@ -542,16 +541,6 @@
   p.then(onModelLoaded.bind(undefined, model), onImportFail);
 }
 
-function fetchUri(uri, onLoad, onError) {
-  var xhr = new XMLHttpRequest();
-  xhr.open('GET', uri, true);
-  xhr.responseType = 'text';
-  xhr.addEventListener('load', onLoad);
-  xhr.addEventListener('error', onError);
-  xhr.send();
-  console.log('GET ' + uri);
-}
-
 function showLoadingOverlay(msg) {
   if (!loadingOverlay) {
     loadingOverlay = new tr.ui.b.Overlay();
@@ -569,102 +558,9 @@
   loadingOverlay = undefined;
 }
 
-function gotReponse() {
-  pendingRequests--;
-  if (pendingRequests === 0) {
-    console.log('Got all timeline parts');
-    updateTimeline(traceObject);
-    hideLoadingOverlay();
-  }
-}
-
-function processTimelineResponse(response) {
-  if (response.error) {
-    // Maybe profiling is disabled.
-    console.log('ERROR ' + response.error.message);
-  } else {
-    var result = response['result'];
-    var newStackFrames = result['stackFrames'];  // Map.
-    var newTraceEvents = result['traceEvents'];  // List.
-
-    // Merge in timeline events.
-    traceObject.traceEvents = traceObject.traceEvents.concat(newTraceEvents);
-    for (var key in newStackFrames) {
-      if (newStackFrames.hasOwnProperty(key)) {
-        traceObject.stackFrames[key] = newStackFrames[key];
-      }
-    }
-  }
-
-  gotReponse();
-}
-
-function fetchTimelineOnLoad(event) {
-  var xhr = event.target;
-  var response = JSON.parse(xhr.responseText);
-  processTimelineResponse(response);
-}
-
-function fetchTimelineOnError(event) {
-  var xhr = event.target;
-  console.log(xhr.statusText);
-  gotReponse();
-}
-
-function fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent) {
-  showLoadingOverlay('Fetching CPU profile(s) from Dart VM');
-  var parser = document.createElement('a');
-  parser.href = vmAddress;
-  pendingRequests += isolateIds.length;
-  for (var i = 0; i < isolateIds.length; i++) {
-    var isolateId = isolateIds[i];
-    var requestUri = 'http://' +
-                     parser.hostname +
-                     ':' +
-                     parser.port +
-                     parser.pathname.replace(/\/ws$/, "") +
-                     '/_getCpuProfileTimeline?tags=None&isolateId=' +
-                     isolateId +
-                     '&timeOriginMicros=' + timeOrigin +
-                     '&timeExtentMicros=' + timeExtent;
-    fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
-  }
-}
-
-function fetchTimeline(vmAddress, isolateIds, mode) {
-  // Reset combined timeline.
-  traceObject = {
-    'stackFrames': {},
-    'traceEvents': []
-  };
-  timelineMode = mode;
-  pendingRequests = 1;
-
-  showLoadingOverlay('Fetching timeline from Dart VM');
-  var parser = document.createElement('a');
-  parser.href = vmAddress;
-  var requestUri = 'http://' +
-                   parser.hostname +
-                   ':' +
-                   parser.port +
-                   parser.pathname.replace(/\/ws$/, "") +
-                   '/getVMTimeline';
-  fetchUri(requestUri, function(event) {
-    // Grab the response.
-    var xhr = event.target;
-    var response = JSON.parse(xhr.responseText);
-    // Extract the time origin and extent.
-    var timeOrigin = response['result']['timeOriginMicros'];
-    var timeExtent = response['result']['timeExtentMicros'];
-    console.assert(Number.isInteger(timeOrigin), timeOrigin);
-    console.assert(Number.isInteger(timeExtent), timeExtent);
-    console.log(timeOrigin);
-    console.log(timeExtent);
-    // fetchCPUProfile.
-    fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent);
-    // This must happen after 'fetchCPUProfile';
-    processTimelineResponse(response, mode);
-  }, fetchTimelineOnError);
+function populateTimeline(traceObject) {
+  updateTimeline(traceObject);
+  hideLoadingOverlay();
 }
 
 function saveTimeline() {
@@ -762,11 +658,9 @@
   timeline_loaded = true;
   console.log('DOMContentLoaded');
   document.getElementById('trace-viewer').highlightVSync = true;
-  if (timeline_vm_address != undefined) {
-    console.log('Triggering delayed timeline refresh.');
-    fetchTimeline(timeline_vm_address, timeline_isolates);
-    timeline_vm_address = undefined;
-    timeline_isolates = undefined;
+  if (traceObject != undefined) {
+    refreshTimeline();
+    traceObject = undefined;
   }
 });
 
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
index c265cfa..2fa3e77 100644
--- a/runtime/observatory/web/timeline_message_handler.js
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -5,11 +5,7 @@
 // This file is loaded before the about:tracing code is loaded so that we have
 // an event listener registered early.
 
-// Used to delay the initial timeline load until the timeline has finished
-// loading.
-timeline_loaded = false;
-timeline_vm_address = undefined;
-timeline_isolates = undefined;
+var traceObject;
 
 function registerForMessages() {
   window.addEventListener("message", onMessage, false);
@@ -25,12 +21,11 @@
   console.log('method: ' + method)
   switch (method) {
     case 'refresh':
-      if (!timeline_loaded) {
-        timeline_vm_address = params['vmAddress'];
-        timeline_isolates = params['isolateIds'];
-        console.log('Delaying timeline refresh until loaded.');
+      if (typeof populateTimeline != 'undefined') {
+        populateTimeline(params);
       } else {
-        fetchTimeline(params['vmAddress'], params['isolateIds']);
+        console.log('populateTimeline is not yet defined');
+        traceObject = params;
       }
     break;
     case 'clear':
diff --git a/runtime/platform/floating_point.h b/runtime/platform/floating_point.h
index 0d29a70..24bcde6 100644
--- a/runtime/platform/floating_point.h
+++ b/runtime/platform/floating_point.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_PLATFORM_FLOATING_POINT_H_
 #define RUNTIME_PLATFORM_FLOATING_POINT_H_
 
+#include <math.h>
+
 inline double fmod_ieee(double x, double y) {
   return fmod(x, y);
 }
diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc
index 7093b19..2cfa649 100644
--- a/runtime/platform/utils.cc
+++ b/runtime/platform/utils.cc
@@ -50,6 +50,68 @@
   return r;
 }
 
+// Implementation according to H.S.Warren's "Hacker's Delight"
+// (Addison Wesley, 2002) Chapter 10 and T.Grablund, P.L.Montogomery's
+// "Division by Invariant Integers Using Multiplication" (PLDI 1994).
+void Utils::CalculateMagicAndShiftForDivRem(int64_t divisor,
+                                            int64_t* magic,
+                                            int64_t* shift) {
+  ASSERT(divisor <= -2 || divisor >= 2);
+  /* The magic number M and shift S can be calculated in the following way:
+   * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
+   * where divisor(d) >= 2.
+   * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
+   * where divisor(d) <= -2.
+   * Thus nc can be calculated like:
+   * nc =  exp + exp       % d - 1, where d >= 2 and exp = 2^63.
+   * nc = -exp + (exp + 1) % d,     where d >= 2 and exp = 2^63.
+   *
+   * So the shift p is the smallest p satisfying
+   * 2^p > nc * (d - 2^p % d), where d >= 2
+   * 2^p > nc * (d + 2^p % d), where d <= -2.
+   *
+   * The magic number M is calculated by
+   * M = (2^p + d - 2^p % d) / d, where d >= 2
+   * M = (2^p - d - 2^p % d) / d, where d <= -2.
+   */
+  int64_t p = 63;
+  const uint64_t exp = 1LL << 63;
+
+  // Initialize the computations.
+  uint64_t abs_d = (divisor >= 0) ? divisor : -divisor;
+  uint64_t sign_bit = static_cast<uint64_t>(divisor) >> 63;
+  uint64_t tmp = exp + sign_bit;
+  uint64_t abs_nc = tmp - 1 - (tmp % abs_d);
+  uint64_t quotient1 = exp / abs_nc;
+  uint64_t remainder1 = exp % abs_nc;
+  uint64_t quotient2 = exp / abs_d;
+  uint64_t remainder2 = exp % abs_d;
+
+  // To avoid handling both positive and negative divisor,
+  // "Hacker's Delight" introduces a method to handle these
+  // two cases together to avoid duplication.
+  uint64_t delta;
+  do {
+    p++;
+    quotient1 = 2 * quotient1;
+    remainder1 = 2 * remainder1;
+    if (remainder1 >= abs_nc) {
+      quotient1++;
+      remainder1 = remainder1 - abs_nc;
+    }
+    quotient2 = 2 * quotient2;
+    remainder2 = 2 * remainder2;
+    if (remainder2 >= abs_d) {
+      quotient2++;
+      remainder2 = remainder2 - abs_d;
+    }
+    delta = abs_d - remainder2;
+  } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
+
+  *magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
+  *shift = p - 64;
+}
+
 uint32_t Utils::StringHash(const char* data, int length) {
   // This implementation is based on the public domain MurmurHash
   // version 2.0. It assumes that the underlying CPU can read from
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 993ff26..7e7aabe 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -150,6 +150,11 @@
   static int CountLeadingZeros(uword x);
   static int CountTrailingZeros(uword x);
 
+  // Computes magic numbers to implement DIV or MOD operator.
+  static void CalculateMagicAndShiftForDivRem(int64_t divisor,
+                                              int64_t* magic,
+                                              int64_t* shift);
+
   // Computes a hash value for the given string.
   static uint32_t StringHash(const char* data, int length);
 
diff --git a/runtime/platform/utils_android.h b/runtime/platform/utils_android.h
index dc16a73..6d91415 100644
--- a/runtime/platform/utils_android.h
+++ b/runtime/platform/utils_android.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_PLATFORM_UTILS_ANDROID_H_
 #define RUNTIME_PLATFORM_UTILS_ANDROID_H_
 
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_android.h directly; use utils.h instead.
+#endif
+
 #include <endian.h>  // NOLINT
 
 namespace dart {
diff --git a/runtime/platform/utils_linux.h b/runtime/platform/utils_linux.h
index a754ef4..4a49a6a 100644
--- a/runtime/platform/utils_linux.h
+++ b/runtime/platform/utils_linux.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_PLATFORM_UTILS_LINUX_H_
 #define RUNTIME_PLATFORM_UTILS_LINUX_H_
 
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_linux.h directly; use utils.h instead.
+#endif
+
 #include <endian.h>  // NOLINT
 
 namespace dart {
diff --git a/runtime/platform/utils_macos.h b/runtime/platform/utils_macos.h
index bc34193..e64711b 100644
--- a/runtime/platform/utils_macos.h
+++ b/runtime/platform/utils_macos.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_PLATFORM_UTILS_MACOS_H_
 #define RUNTIME_PLATFORM_UTILS_MACOS_H_
 
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_macos.h directly; use utils.h instead.
+#endif
+
 #include <AvailabilityMacros.h>
 #include <libkern/OSByteOrder.h>  // NOLINT
 
diff --git a/runtime/platform/utils_win.h b/runtime/platform/utils_win.h
index c3a67e7..ba5c9cc 100644
--- a/runtime/platform/utils_win.h
+++ b/runtime/platform/utils_win.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_PLATFORM_UTILS_WIN_H_
 #define RUNTIME_PLATFORM_UTILS_WIN_H_
 
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_win.h directly; use utils.h instead.
+#endif
+
 #include <intrin.h>
 #include <stdlib.h>
 
diff --git a/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart b/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart
new file mode 100644
index 0000000..0a6f667
--- /dev/null
+++ b/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=
+// VMOptions=--early-round-trip-serialization
+// VMOptions=--late-round-trip-serialization
+// VMOptions=--early-round-trip-serialization --late-round-trip-serialization
+// VMOptions=--deterministic
+// VMOptions=--deterministic --early-round-trip-serialization
+// VMOptions=--deterministic --late-round-trip-serialization
+// VMOptions=--deterministic --early-round-trip-serialization --late-round-trip-serialization
+
+// Just use the existing hello world test for now.
+// TODO(36882): Add more interesting code as the deserializer grows.
+import 'hello_world_test.dart' as test;
+
+main(args) {
+  test.main();
+}
diff --git a/runtime/tests/vm/dart/internal_platform_library_import_test.dart b/runtime/tests/vm/dart/internal_platform_library_import_test.dart
new file mode 100644
index 0000000..7f99459
--- /dev/null
+++ b/runtime/tests/vm/dart/internal_platform_library_import_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:_internal';
+
+void main(List<String> args) {
+  // Ensure we can import and use members of `dart:_internal`.
+  print(unsafeCast);
+}
diff --git a/runtime/tests/vm/dart/isolates/spawn_function_test.dart b/runtime/tests/vm/dart/isolates/spawn_function_test.dart
new file mode 100644
index 0000000..f2a85ea
--- /dev/null
+++ b/runtime/tests/vm/dart/isolates/spawn_function_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--enable-isolate-groups
+// VMOptions=--no-enable-isolate-groups
+
+import 'dart:isolate';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+void isolateEntry(args) {
+  final SendPort sendPort = args;
+  sendPort.send('hello world');
+}
+
+main() async {
+  final port = ReceivePort();
+  final exitPort = ReceivePort();
+
+  await Isolate.spawn(isolateEntry, port.sendPort, onExit: exitPort.sendPort);
+
+  final messages = StreamIterator(port);
+  Expect.isTrue(await messages.moveNext());
+  Expect.equals('hello world', messages.current);
+  await messages.cancel();
+
+  final exit = StreamIterator(exitPort);
+  Expect.isTrue(await exit.moveNext());
+  await exit.cancel();
+}
diff --git a/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart b/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart
new file mode 100644
index 0000000..a3edcce
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--deterministic --optimization-counter-threshold=5 --use-bytecode-compiler
+//
+// Test that block merging takes phis into account.
+//
+// The problem only reproduces with bytecode compiler (--use-bytecode-compiler)
+// as bytecode doesn't have backward branches for the redundant loops.
+// OSR handling code inserts Phi instructions to JoinEntry
+// even when there is only one predecessor. This results in a flow graph
+// suitable for block merging with a successor block containing Phi.
+
+import 'package:expect/expect.dart';
+
+void testBottomUpInference() {
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+  Expect.type<List<int>>([for (; false;) 1]);
+}
+
+main() {
+  testBottomUpInference();
+}
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index e3393a3..f6ece6d 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -88,7 +88,7 @@
   }
   final int actual = await File(snapshotPath).length();
   final int expected = profile.accountedBytes;
-  Expect.isTrue((actual - expected).abs() / actual < 0.01);
+  Expect.isTrue((actual - expected).abs() / actual < 0.02);
 }
 
 Match matchComplete(RegExp regexp, String line) {
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index da4d33f..22c5b32 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -72,9 +72,6 @@
 dart/appjit_bytecode_simple_test: Skip # Issue 34393.
 dart/disassemble_determinism_test: Slow # Times out on slower bots.
 
-[ !$strong ]
-dart/callee_side_type_checks_test: SkipByDesign
-
 [ $arch == ia32 && $mode == debug && $system == windows ]
 dart/transferable_test: Skip # This is performance test and somehow debug win ia32 bot's performance is unpredictable
 
@@ -137,9 +134,6 @@
 [ $runtime == vm && $system == macos && ($compiler == dartk || $compiler == dartkb) ]
 cc/IsolateReload_LibraryLookup: Fail, Crash
 
-[ $runtime == vm && !$checked && !$strong ]
-dart/redirection_type_shuffling_test/00: MissingCompileTimeError
-
 [ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
 cc/DartAPI_LoadLibrary: Fail, Crash # Issue 33048.
 cc/DebuggerAPI_BreakpointStubPatching: Fail
@@ -164,14 +158,6 @@
 [ $checked && ($compiler == dartk || $compiler == dartkb) ]
 dart/redirection_type_shuffling_test/00: Pass # Works in --checked mode but not in --strong mode.
 
-[ $strong && ($compiler == dartk || $compiler == dartkb) ]
-cc/DartGeneratedArrayLiteralMessages: Crash # Issue 32190
-cc/FullSnapshot1: Crash # Issue 32190
-cc/IsolateReload_LibraryLookup: Fail, Crash # Issue 32190
-cc/MismatchedSnapshotKinds: Fail, Crash, OK # Script snapshots not supported in Dart 2
-cc/ScriptSnapshot1: Fail, Crash, OK # Script snapshots not supported in Dart 2
-cc/ScriptSnapshotsUpdateSubclasses: Fail, Crash, OK # Script snapshots not supported in Dart 2
-
 [ ($arch == simarm || $arch == simarm64 || $arch == simdbc || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
 dart/appjit*: SkipSlow # DFE too slow
 
@@ -186,7 +172,7 @@
 dart/data_uri_spawn_test: Skip # Timeout
 dart/kernel_determinism_test: SkipSlow
 
-[ $arch == arm || $arch == arm64 || $compiler != dartkp ]
+[ $arch == arm || $arch == arm64 || $builder_tag == crossword || $compiler != dartkp ]
 dart/v8_snapshot_profile_writer_test: SkipByDesign # Only relevant for AOT. Doesn't work in cross-compilation (has to run on the host).
 
 [ $arch == arm || $arch == ia32 || $arch == simarm || $arch == simdbc || $arch == simdbc64 ]
@@ -250,6 +236,12 @@
 
 [ $compiler == dartk || $compiler == dartkb ]
 cc/DartAPI_New: Fail # Issue #33041
+cc/DartGeneratedArrayLiteralMessages: Crash # Issue 32190
+cc/FullSnapshot1: Crash # Issue 32190
+cc/IsolateReload_LibraryLookup: Fail, Crash # Issue 32190
+cc/MismatchedSnapshotKinds: Fail, Crash, OK # Script snapshots not supported in Dart 2
+cc/ScriptSnapshot1: Fail, Crash, OK # Script snapshots not supported in Dart 2
+cc/ScriptSnapshotsUpdateSubclasses: Fail, Crash, OK # Script snapshots not supported in Dart 2
 dart/redirection_type_shuffling_test/00: RuntimeError, Pass
 dart/redirection_type_shuffling_test/none: RuntimeError
 
diff --git a/runtime/tools/bin_to_coff.py b/runtime/tools/bin_to_coff.py
index 1925bcd..c8a8ebc 100644
--- a/runtime/tools/bin_to_coff.py
+++ b/runtime/tools/bin_to_coff.py
@@ -4,6 +4,8 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
+# See also "PE Format" at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+
 import argparse
 from ctypes import create_string_buffer
 from struct import *
@@ -19,6 +21,7 @@
 SECTION_HEADER_TEXT = 0x20  # Contains executable code
 SECTION_HEADER_DATA = 0x40  # Contains only initialized data
 SECTION_HEADER_BSS = 0x80  # Contains uninitialized data
+SECTION_HEADER_ALIGN_32BYTES = 0x600000
 
 # FILE HEADER FORMAT
 # typedef struct {
@@ -176,17 +179,18 @@
     offset += FILE_HEADER_SIZE
 
     section_name = SECTION_NAME_RODATA
-    section_type = SECTION_HEADER_DATA
+    section_flags = SECTION_HEADER_DATA
     if args.executable:
         section_name = SECTION_NAME_TEXT
-        section_type = SECTION_HEADER_TEXT
+        section_flags = SECTION_HEADER_TEXT
+    section_flags |= SECTION_HEADER_ALIGN_32BYTES
 
     # Populate the section header for a single section.
     pack_into(SECTION_HEADER_FORMAT, buff, offset, section_name, SECTION_PADDR,
               SECTION_VADDR, section_size + size_symbol_size,
               SECTION_RAW_DATA_PTR, SECTION_RELOCATION_PTR,
               SECTION_LINE_NUMS_PTR, SECTION_NUM_RELOCATION,
-              SECTION_NUM_LINE_NUMS, section_type)
+              SECTION_NUM_LINE_NUMS, section_flags)
     offset += SECTION_HEADER_SIZE
 
     # Copy the binary data.
diff --git a/runtime/tools/dartfuzz/analysis_options.yaml b/runtime/tools/dartfuzz/analysis_options.yaml
new file mode 100644
index 0000000..73dd727
--- /dev/null
+++ b/runtime/tools/dartfuzz/analysis_options.yaml
@@ -0,0 +1,6 @@
+include: package:pedantic/analysis_options.yaml
+
+linter:
+  rules:
+    - directives_ordering
+    - prefer_generic_function_type_aliases
diff --git a/runtime/tools/dartfuzz/collect_data.py b/runtime/tools/dartfuzz/collect_data.py
index 5d4f677..25b5f5d 100755
--- a/runtime/tools/dartfuzz/collect_data.py
+++ b/runtime/tools/dartfuzz/collect_data.py
@@ -32,91 +32,106 @@
 P_DIV = re.compile("(Isolate.+? !DIVERGENCE! (\n|.)+?)Isolate ", re.MULTILINE)
 
 # Matches shard raw stdout to extract report summaries.
-P_SUM = re.compile(r"^Tests: (\d+) Success: (\d+) Not-Run: (\d+): "
-                   r"Time-Out: (\d+) Divergences: (\d+)$", re.MULTILINE)
+P_SUM = re.compile(
+    r"^Tests: (\d+) Success: (\d+) "
+    r"\(Rerun: (\d+)\) Skipped: (\d+) "
+    r"Timeout: (\d+) Divergences: (\d+)", re.MULTILINE)
 
 # Matches uri to extract shard number.
 P_SHARD = re.compile(r".*make_a_fuzz_shard_(\d+)")
 
 
 def get_shard_links(uri):
-  links = []
-  resp = requests.get(uri)
-  soup = BeautifulSoup(resp.text, "html.parser")
-  for a in soup.findAll("a"):
-    if a.text == "raw":
-      href = a["href"]
-      if ("make_a_fuzz_shard" in href and
-          "__trigger__" not in href):
-        links.append(href)
-  return links
+    links = []
+    resp = requests.get(uri)
+    soup = BeautifulSoup(resp.text, "html.parser")
+    for a in soup.findAll("a"):
+        if a.text == "raw":
+            href = a["href"]
+            if ("make_a_fuzz_shard" in href and "__trigger__" not in href):
+                links.append(href)
+    return links
 
 
 def print_reencoded(text):
-  # Re-encoding avoids breaking some terminals.
-  print(text.encode("ascii", errors="ignore").decode("unicode-escape"))
+    # Re-encoding avoids breaking some terminals.
+    print(text.encode("ascii", errors="ignore").decode("unicode-escape"))
 
 
 def print_output_all(text):
-  print_reencoded(text)
+    print_reencoded(text)
 
 
-def print_output_div(shard, text):
-  sys.stderr.write("Shard: " + shard + "  \r")
-  m = P_DIV.findall(text)
-  if m:
-    print("Shard: " + shard)
-    for x in m:
-      print_reencoded(x[0])
+def print_output_div(shard, text, keywords):
+    sys.stderr.write("Shard: " + shard + "  \r")
+    m = P_DIV.findall(text)
+    if m:
+        for x in m:
+            keep = True
+            for word in keywords:
+                if word in x[0]:
+                    keep = False
+                    break
+            if keep:
+                print_reencoded(x[0])
 
 
-def print_output_sum(shard, text, s=[0, 0, 0, 0, 0], divs=[]):
-  m = P_SUM.findall(text)
-  if not m:
-    sys.stderr.write("Failed to parse shard %s stdout for summary" % shard)
-    return
-  for test in m:
-    if int(test[-1]) == 1:
-      divs.append(shard)
-    for i in range(len(s)):
-      s[i] += int(test[i])
-  print("Tests: %d Success: %d Not-Run: %d Time-Out: %d Divergences: %d "
-        "(failing shards: %s)    \r"
-        % tuple(s + [", ".join(divs) if divs else "none"]), end="")
+def print_output_sum(shard, text, s=[0, 0, 0, 0, 0, 0], divs=[]):
+    m = P_SUM.findall(text)
+    if not m:
+        sys.stderr.write("Failed to parse shard %s stdout for summary" % shard)
+        return
+    for test in m:
+        if int(test[-1]) == 1:
+            divs.append(shard)
+        for i in range(len(s)):
+            s[i] += int(test[i])
+    print(
+        "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d Divergences: %d"
+        "(failing shards: %s)    \r" %
+        tuple(s + [", ".join(divs) if divs else "none"]),
+        end="")
 
 
-def get_stats(uri, output_type):
-  resp = requests.get(uri)
+def get_stats(uri, output_type, keywords):
+    resp = requests.get(uri)
 
-  if output_type == "all":
-    print_output_all(resp.text)
-  elif output_type == "div":
-    shard = P_SHARD.findall(uri)[0]
-    print_output_div(shard, resp.text)
-  elif output_type == "sum":
-    shard = P_SHARD.findall(uri)[0]
-    print_output_sum(shard, resp.text)
+    if output_type == "all":
+        print_output_all(resp.text)
+    elif output_type == "div":
+        shard = P_SHARD.findall(uri)[0]
+        print_output_div(shard, resp.text, keywords)
+    elif output_type == "sum":
+        shard = P_SHARD.findall(uri)[0]
+        print_output_sum(shard, resp.text)
 
 
 def main():
-  parser = argparse.ArgumentParser(description=__doc__)
-  parser.add_argument(
-      "--type",
-      choices=("div", "sum", "all"),
-      required=True,
-      help="Select output type (div: divergence report, sum: summary, all: complete stdout)"
-  )
-  parser.add_argument(
-      "uri",
-      type=str,
-      help="Uri of one make_a_fuzz run from https://ci.chromium.org/p/dart/builders/ci.sandbox/fuzz-linux."
-  )
-  args = parser.parse_args()
-  shard_links = get_shard_links(args.uri)
-  for link in shard_links:
-    get_stats(link, args.type)
-  print("")
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+        "--type",
+        choices=("div", "sum", "all"),
+        required=True,
+        help=
+        "Select output type (div: divergence report, sum: summary, all: complete stdout)"
+    )
+    parser.add_argument(
+        "--filter",
+        nargs="+",
+        default=[],
+        help="Do not include divergences containing these keywords.")
+    parser.add_argument(
+        "uri",
+        type=str,
+        help=
+        "Uri of one make_a_fuzz run from https://ci.chromium.org/p/dart/builders/ci.sandbox/fuzz-linux."
+    )
+    args = parser.parse_args()
+    shard_links = get_shard_links(args.uri)
+    for link in shard_links:
+        get_stats(link, args.type, args.filter)
+    print("")
 
 
 if __name__ == "__main__":
-  main()
+    main()
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index 97b9683..cc97ad8 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -9,11 +9,12 @@
 
 import 'dartfuzz_values.dart';
 import 'dartfuzz_api_table.dart';
+import 'dartfuzz_ffiapi.dart';
 
 // Version of DartFuzz. Increase this each time changes are made
 // to preserve the property that a given version of DartFuzz yields
 // the same fuzzed program for a deterministic random seed.
-const String version = '1.23';
+const String version = '1.39';
 
 // Restriction on statements and expressions.
 const int stmtLength = 2;
@@ -27,30 +28,83 @@
 const fieldName = 'fld';
 const methodName = 'foo';
 
+/// Class that specifies the api for calling library and ffi functions (if
+/// enabled).
+class DartApi {
+  DartApi(bool ffi)
+      : intLibs = [
+          if (ffi) ...[
+            DartLib('intComputation', 'VIIII'),
+            DartLib('takeMaxUint16', 'VI'),
+            DartLib('sumPlus42', 'VII'),
+            DartLib('returnMaxUint8', 'VV'),
+            DartLib('returnMaxUint16', 'VV'),
+            DartLib('returnMaxUint32', 'VV'),
+            DartLib('returnMinInt8', 'VV'),
+            DartLib('returnMinInt16', 'VV'),
+            DartLib('returnMinInt32', 'VV'),
+            DartLib('takeMinInt16', 'VI'),
+            DartLib('takeMinInt32', 'VI'),
+            DartLib('uintComputation', 'VIIII'),
+            DartLib('sumSmallNumbers', 'VIIIIII'),
+            DartLib('takeMinInt8', 'VI'),
+            DartLib('takeMaxUint32', 'VI'),
+            DartLib('takeMaxUint8', 'VI'),
+            DartLib('minInt64', 'VV'),
+            DartLib('minInt32', 'VV'),
+            // Use small int to avoid overflow divergences due to size
+            // differences in intptr_t on 32-bit and 64-bit platforms.
+            DartLib('sumManyIntsOdd', 'Viiiiiiiiiii'),
+            DartLib('sumManyInts', 'Viiiiiiiiii'),
+            DartLib('regress37069', 'Viiiiiiiiiii'),
+          ],
+          ...DartLib.intLibs,
+        ],
+        doubleLibs = [
+          if (ffi) ...[
+            DartLib('times1_337Float', 'VD'),
+            DartLib('sumManyDoubles', 'VDDDDDDDDDD'),
+            DartLib('times1_337Double', 'VD'),
+            DartLib('sumManyNumbers', 'VIDIDIDIDIDIDIDIDIDID'),
+            DartLib('inventFloatValue', 'VV'),
+            DartLib('smallDouble', 'VV'),
+          ],
+          ...DartLib.doubleLibs,
+        ];
+
+  final boolLibs = DartLib.boolLibs;
+  final stringLibs = DartLib.stringLibs;
+  final listLibs = DartLib.listLibs;
+  final setLibs = DartLib.setLibs;
+  final mapLibs = DartLib.mapLibs;
+  final List<DartLib> intLibs;
+  final List<DartLib> doubleLibs;
+}
+
 /// Class that generates a random, but runnable Dart program for fuzz testing.
 class DartFuzz {
   DartFuzz(this.seed, this.fp, this.ffi, this.file);
 
   void run() {
     // Initialize program variables.
-    rand = new Random(seed);
+    rand = Random(seed);
     indent = 0;
     nest = 0;
     currentClass = null;
     currentMethod = null;
+    // Setup the library and ffi api.
+    api = DartApi(ffi);
     // Setup the types.
-    localVars = new List<DartType>();
-    iterVars = new List<String>();
+    localVars = <DartType>[];
+    iterVars = <String>[];
     globalVars = fillTypes1();
     globalVars.addAll(DartType.allTypes); // always one each
     globalMethods = fillTypes2();
-    classFields = fillTypes2();
+    classFields = fillTypes2(limit: 8);
     classMethods = fillTypes3(classFields.length);
+    classParents = <int>[];
     // Setup optional ffi methods and types.
-    List<bool> ffiStatus = new List<bool>();
-    for (var m in globalMethods) {
-      ffiStatus.add(false);
-    }
+    final ffiStatus = <bool>[for (final _ in globalMethods) false];
     if (ffi) {
       List<List<DartType>> globalMethodsFfi = fillTypes2(isFfi: true);
       for (var m in globalMethodsFfi) {
@@ -69,7 +123,7 @@
     assert(currentMethod == null);
     assert(indent == 0);
     assert(nest == 0);
-    assert(localVars.length == 0);
+    assert(localVars.isEmpty);
   }
 
   //
@@ -91,7 +145,10 @@
     emitLn("import 'dart:isolate';");
     emitLn("import 'dart:math';");
     emitLn("import 'dart:typed_data';");
-    if (ffi) emitLn("import 'dart:ffi' as ffi;");
+    if (ffi) {
+      emitLn("import 'dart:ffi' as ffi;");
+      emitLn(DartFuzzFfiApi.ffiapi);
+    }
   }
 
   void emitFfiCast(String dartFuncName, String ffiFuncName, String typeName,
@@ -106,7 +163,7 @@
     }
     emit(') ${dartFuncName} = ' +
         'ffi.Pointer.fromFunction<${typeName}>(${ffiFuncName}, ');
-    emitLiteral(0, pars[0]);
+    emitLiteral(0, pars[0], smallPositiveValue: true);
     emitLn(').cast<ffi.NativeFunction<${typeName}>>().asFunction();');
   }
 
@@ -123,13 +180,21 @@
         emitLn('${method[0].name} $name$i(', newline: false);
       }
       emitParDecls(method);
+      if (!isFfiMethod && rand.nextInt(10) == 0) {
+        // Emit a method using "=>" syntax.
+        emit(') => ');
+        emitExpr(0, method[0]);
+        emit(';', newline: true);
+        currentMethod = null;
+        continue;
+      }
       emit(') {', newline: true);
       indent += 2;
-      assert(localVars.length == 0);
+      assert(localVars.isEmpty);
       if (emitStatements(0)) {
         emitReturn();
       }
-      assert(localVars.length == 0);
+      assert(localVars.isEmpty);
       indent -= 2;
       emitLn('}');
       if (isFfiMethod) {
@@ -144,7 +209,25 @@
   void emitClasses() {
     assert(classFields.length == classMethods.length);
     for (int i = 0; i < classFields.length; i++) {
-      emitLn('class X$i ${i == 0 ? "" : "extends X${i - 1}"} {');
+      if (i == 0) {
+        classParents.add(-1);
+        emitLn('class X0 {');
+      } else {
+        final int parentClass = rand.nextInt(i);
+        classParents.add(parentClass);
+        if (rand.nextInt(2) != 0) {
+          // Inheritance
+          emitLn('class X$i extends X${parentClass} {');
+        } else {
+          // Mixin
+          if (classParents[parentClass] >= 0) {
+            emitLn(
+                'class X$i extends X${classParents[parentClass]} with X${parentClass} {');
+          } else {
+            emitLn('class X$i with X${parentClass} {');
+          }
+        }
+      }
       indent += 2;
       emitVarDecls('$fieldName${i}_', classFields[i]);
       currentClass = i;
@@ -154,9 +237,9 @@
       if (i > 0) {
         emitLn('super.run();');
       }
-      assert(localVars.length == 0);
+      assert(localVars.isEmpty);
       emitStatements(0);
-      assert(localVars.length == 0);
+      assert(localVars.isEmpty);
       indent -= 2;
       emitLn('}');
       indent -= 2;
@@ -166,16 +249,68 @@
     }
   }
 
+  void emitLoadFfiLib() {
+    if (ffi) {
+      emitLn(
+          '// The following throws an uncaught exception if the ffi library ' +
+              'is not found.');
+      emitLn(
+          '// By not catching this exception, we terminate the program with ' +
+              'a full stack trace');
+      emitLn('// which, in turn, flags the problem prominently');
+      emitLn('if (ffiTestFunctions == null) {');
+      indent += 2;
+      emitLn('print(\'Did not load ffi test functions\');');
+      indent -= 2;
+      emitLn('}');
+    }
+  }
+
   void emitMain() {
     emitLn('main() {');
     indent += 2;
+
+    emitLoadFfiLib();
+
+    // Call each global method once.
+    for (int i = 0; i < globalMethods.length; i++) {
+      emitLn('try {');
+      indent += 2;
+      emitLn("", newline: false);
+      emitCall(1, "$methodName${i}", globalMethods[i]);
+      emit(";", newline: true);
+      indent -= 2;
+      emitLn('} catch (exception, stackTrace) {');
+      indent += 2;
+      emitLn("print('$methodName$i throws');");
+      indent -= 2;
+      emitLn('}');
+    }
+
+    // Call each class method once.
+    for (int i = 0; i < classMethods.length; i++) {
+      for (int j = 0; j < classMethods[i].length; j++) {
+        emitLn('try {');
+        indent += 2;
+        emitLn("", newline: false);
+        emitCall(1, "X${i}().$methodName${i}_${j}", classMethods[i][j]);
+        emit(";", newline: true);
+        indent -= 2;
+        emitLn('} catch (exception, stackTrace) {');
+        indent += 2;
+        emitLn("print('X${i}().$methodName${i}_${j}() throws');");
+        indent -= 2;
+        emitLn('}');
+      }
+    }
+
     emitLn('try {');
     indent += 2;
-    emitLn('new X${classFields.length - 1}().run();');
+    emitLn('X${classFields.length - 1}().run();');
     indent -= 2;
     emitLn('} catch (exception, stackTrace) {');
     indent += 2;
-    emitLn("print('throws');");
+    emitLn("print('X${classFields.length - 1}().run() throws');");
     indent -= 2;
     emitLn('} finally {');
     indent += 2;
@@ -356,7 +491,8 @@
   bool emitForEach(int depth) {
     final int i = localVars.length;
     emitLn("", newline: false);
-    emitScalarVar(DartType.INT_STRING_MAP, isLhs: true);
+    final emittedVar = emitScalarVar(DartType.INT_STRING_MAP, isLhs: false);
+    iterVars.add(emittedVar);
     emit('.forEach(($localName$i, $localName${i + 1}) {\n');
     indent += 2;
     final int nestTmp = nest;
@@ -467,7 +603,7 @@
     emit(';', newline: true);
     indent += 2;
     localVars.add(tp);
-    bool b = emitStatements(depth + 1);
+    emitStatements(depth + 1);
     localVars.removeLast();
     indent -= 2;
     emitLn('}');
@@ -632,8 +768,8 @@
 
   void emitCollectionElement(int depth, DartType tp) {
     int r = depth <= exprDepth ? rand.nextInt(10) : 10;
+    // TODO(ajcbik): renable, https://github.com/dart-lang/sdk/issues/38231
     switch (r + 3) {
-      // TODO(ajcbik): enable when on by default
       // Favors elements over control-flow collections.
       case 0:
         emit('...'); // spread
@@ -695,11 +831,15 @@
     emit(tp == DartType.INT_LIST ? ' ]' : ' }');
   }
 
-  void emitLiteral(int depth, DartType tp) {
+  void emitLiteral(int depth, DartType tp, {bool smallPositiveValue = false}) {
     if (tp == DartType.BOOL) {
       emitBool();
     } else if (tp == DartType.INT) {
-      emitInt();
+      if (smallPositiveValue) {
+        emitSmallPositiveInt();
+      } else {
+        emitInt();
+      }
     } else if (tp == DartType.DOUBLE) {
       emitDouble();
     } else if (tp == DartType.STRING) {
@@ -713,9 +853,9 @@
     }
   }
 
-  void emitScalarVar(DartType tp, {bool isLhs = false}) {
+  String emitScalarVar(DartType tp, {bool isLhs = false}) {
     // Collect all choices from globals, fields, locals, and parameters.
-    Set<String> choices = new Set<String>();
+    Set<String> choices = <String>{};
     for (int i = 0; i < globalVars.length; i++) {
       if (tp == globalVars[i]) choices.add('$varName$i');
     }
@@ -734,19 +874,21 @@
         if (tp == proto[i]) choices.add('$paramName$i');
       }
     }
-    // Remove possible modification of the iteration variable from the loop
-    // body.
+    // Make modification of the iteration variable from the loop
+    // body less likely.
     if (isLhs) {
-      if (rand.nextInt(10) != 0) {
+      if (rand.nextInt(100) != 0) {
         Set<String> cleanChoices = choices.difference(Set.from(iterVars));
-        if (cleanChoices.length > 0) {
+        if (cleanChoices.isNotEmpty) {
           choices = cleanChoices;
         }
       }
     }
     // Then pick one.
-    assert(choices.length > 0);
-    emit('${choices.elementAt(rand.nextInt(choices.length))}');
+    assert(choices.isNotEmpty);
+    final emittedVar = '${choices.elementAt(rand.nextInt(choices.length))}';
+    emit(emittedVar);
+    return emittedVar;
   }
 
   void emitSubscriptedVar(int depth, DartType tp, {bool isLhs = false}) {
@@ -894,13 +1036,18 @@
     }
   }
 
+  // Emit call to a specific method.
+  void emitCall(int depth, String name, List<DartType> proto) {
+    emit(name);
+    emitExprList(depth + 1, proto);
+  }
+
   // Helper for a method call.
   bool pickedCall(
       int depth, DartType tp, String name, List<List<DartType>> protos, int m) {
     for (int i = m - 1; i >= 0; i--) {
       if (tp == protos[i][0]) {
-        emit('$name$i');
-        emitExprList(depth + 1, protos[i]);
+        emitCall(depth + 1, "$name$i", protos[i]);
         return true;
       }
     }
@@ -917,13 +1064,30 @@
         return;
       }
     } else {
-      // Inside a class: try to call backwards in class methods first.
-      final int m1 = currentMethod == null
-          ? classMethods[currentClass].length
-          : currentMethod;
+      int classIndex = currentClass;
+      // Chase randomly up in class hierarchy.
+      while (classParents[classIndex] > 0) {
+        if (rand.nextInt(2) == 0) {
+          break;
+        }
+        classIndex = classParents[classIndex];
+      }
+      int m1 = 0;
+      // Inside a class: try to call backwards into current or parent class
+      // methods first.
+      if (currentMethod == null || classIndex != currentClass) {
+        // If currently emitting the 'run' method or calling into a parent class
+        // pick any of the current or parent class methods respectively.
+        m1 = classMethods[classIndex].length;
+      } else {
+        // If calling into the current class from any method other than 'run'
+        // pick one of the already emitted methods
+        // (to avoid infinite recursions).
+        m1 = currentMethod;
+      }
       final int m2 = globalMethods.length;
-      if (pickedCall(depth, tp, '$methodName${currentClass}_',
-              classMethods[currentClass], m1) ||
+      if (pickedCall(depth, tp, '$methodName${classIndex}_',
+              classMethods[classIndex], m1) ||
           pickedCall(depth, tp, methodName, globalMethods, m2)) {
         return;
       }
@@ -1058,22 +1222,21 @@
   // Get a library method that returns given type.
   DartLib getLibraryMethod(DartType tp) {
     if (tp == DartType.BOOL) {
-      return oneOf(DartLib.boolLibs);
+      return oneOf(api.boolLibs);
     } else if (tp == DartType.INT) {
-      return oneOf(DartLib.intLibs);
+      return oneOf(api.intLibs);
     } else if (tp == DartType.DOUBLE) {
-      return oneOf(DartLib.doubleLibs);
+      return oneOf(api.doubleLibs);
     } else if (tp == DartType.STRING) {
-      return oneOf(DartLib.stringLibs);
+      return oneOf(api.stringLibs);
     } else if (tp == DartType.INT_LIST) {
-      return oneOf(DartLib.listLibs);
+      return oneOf(api.listLibs);
     } else if (tp == DartType.INT_SET) {
-      return oneOf(DartLib.setLibs);
+      return oneOf(api.setLibs);
     } else if (tp == DartType.INT_STRING_MAP) {
-      return oneOf(DartLib.mapLibs);
-    } else {
-      assert(false);
+      return oneOf(api.mapLibs);
     }
+    throw ArgumentError('Invalid DartType: $tp');
   }
 
   // Emit a library argument, possibly subject to restrictions.
@@ -1082,7 +1245,7 @@
       case 'B':
         emitExpr(depth, DartType.BOOL);
         break;
-      case 'i':
+      case 'i': // emit small int
         emitSmallPositiveInt();
         break;
       case 'I':
@@ -1094,12 +1257,7 @@
       case 'S':
         emitExpr(depth, DartType.STRING);
         break;
-      case 's':
-        // Emit string literal of 2 characters maximum length
-        // for 'small string' parameters to avoid recursively constructed
-        // strings which might lead to exponentially growing data structures
-        // e.g. loop { var = 'x'.padLeft(8, var); }
-        // TODO (felih): detect recursion to eliminate such cases specifically
+      case 's': // emit small string
         emitString(length: 2);
         break;
       case 'L':
@@ -1112,7 +1270,7 @@
         emitExpr(depth, DartType.INT_STRING_MAP);
         break;
       default:
-        assert(false);
+        throw ArgumentError('Invalid p value: $p');
     }
   }
 
@@ -1135,32 +1293,33 @@
         return DartType.INT_LIST;
       case 5:
         return DartType.INT_SET;
-      case 6:
+      default:
         return DartType.INT_STRING_MAP;
     }
   }
 
   List<DartType> fillTypes1({bool isFfi = false}) {
-    List<DartType> list = new List<DartType>();
+    final list = <DartType>[];
     for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
-      if (isFfi)
+      if (isFfi) {
         list.add(fp ? oneOf([DartType.INT, DartType.DOUBLE]) : DartType.INT);
-      else
+      } else {
         list.add(getType());
+      }
     }
     return list;
   }
 
-  List<List<DartType>> fillTypes2({bool isFfi = false}) {
-    List<List<DartType>> list = new List<List<DartType>>();
-    for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
+  List<List<DartType>> fillTypes2({bool isFfi = false, int limit = 4}) {
+    final list = <List<DartType>>[];
+    for (int i = 0, n = 1 + rand.nextInt(limit); i < n; i++) {
       list.add(fillTypes1(isFfi: isFfi));
     }
     return list;
   }
 
   List<List<List<DartType>>> fillTypes3(int n) {
-    List<List<List<DartType>>> list = new List<List<List<DartType>>>();
+    final list = <List<List<DartType>>>[];
     for (int i = 0; i < n; i++) {
       list.add(fillTypes2());
     }
@@ -1244,6 +1403,9 @@
   // File used for output.
   final RandomAccessFile file;
 
+  // Library and ffi api.
+  DartApi api;
+
   // Program variables.
   Random rand;
   int indent;
@@ -1270,6 +1432,9 @@
 
   // Prototypes of all methods over all classes (first element is return type).
   List<List<List<DartType>>> classMethods;
+
+  // Parent class indices for all classes.
+  List<int> classParents;
 }
 
 // Generate seed. By default (no user-defined nonzero seed given),
@@ -1278,7 +1443,7 @@
 int getSeed(String userSeed) {
   int seed = int.parse(userSeed);
   if (seed == 0) {
-    Random rand = new Random();
+    Random rand = Random();
     while (seed == 0) {
       seed = rand.nextInt(1 << 32);
     }
@@ -1288,7 +1453,7 @@
 
 /// Main driver when dartfuzz.dart is run stand-alone.
 main(List<String> arguments) {
-  final parser = new ArgParser()
+  final parser = ArgParser()
     ..addOption('seed',
         help: 'random seed (0 forces time-based seed)', defaultsTo: '0')
     ..addFlag('fp', help: 'enables floating-point operations', defaultsTo: true)
@@ -1299,8 +1464,8 @@
     final seed = getSeed(results['seed']);
     final fp = results['fp'];
     final ffi = results['ffi'];
-    final file = new File(results.rest.single).openSync(mode: FileMode.write);
-    new DartFuzz(seed, fp, ffi, file).run();
+    final file = File(results.rest.single).openSync(mode: FileMode.write);
+    DartFuzz(seed, fp, ffi, file).run();
     file.closeSync();
   } catch (e) {
     print('Usage: dart dartfuzz.dart [OPTIONS] FILENAME\n${parser.usage}\n$e');
diff --git a/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart b/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart
new file mode 100644
index 0000000..cb34993
--- /dev/null
+++ b/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart
@@ -0,0 +1,243 @@
+// 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.
+
+// Contains the Dart FFI interface to the c-library defined in
+// sdk/runtime/bin/ffi_test/ffi_test_functions.cc.
+// The code contained in this class is intended to be added to Dart programs
+// generated by dartfuzz.dart.
+class DartFuzzFfiApi {
+  static const ffiapi = """
+
+ffi.DynamicLibrary ffiTestFunctions =
+    ffi.DynamicLibrary.open("libffi_test_functions.so");
+
+typedef NativeBinaryOp = ffi.Int32 Function(ffi.Int32, ffi.Int32);
+typedef BinaryOp = int Function(int, int);
+BinaryOp sumPlus42 =
+    ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
+
+typedef NativeReturnMaxUint8 = ffi.Uint8 Function();
+int Function() returnMaxUint8 = ffiTestFunctions
+    .lookup("ReturnMaxUint8")
+    .cast<ffi.NativeFunction<NativeReturnMaxUint8>>()
+    .asFunction();
+
+typedef NativeReturnMaxUint16 = ffi.Uint16 Function();
+int Function() returnMaxUint16 = ffiTestFunctions
+    .lookup("ReturnMaxUint16")
+    .cast<ffi.NativeFunction<NativeReturnMaxUint16>>()
+    .asFunction();
+
+typedef NativeReturnMaxUint32 = ffi.Uint32 Function();
+int Function() returnMaxUint32 = ffiTestFunctions
+    .lookup("ReturnMaxUint32")
+    .cast<ffi.NativeFunction<NativeReturnMaxUint32>>()
+    .asFunction();
+
+typedef NativeReturnMinInt8 = ffi.Int8 Function();
+int Function() returnMinInt8 = ffiTestFunctions
+    .lookup("ReturnMinInt8")
+    .cast<ffi.NativeFunction<NativeReturnMinInt8>>()
+    .asFunction();
+
+typedef NativeReturnMinInt16 = ffi.Int16 Function();
+int Function() returnMinInt16 = ffiTestFunctions
+    .lookup("ReturnMinInt16")
+    .cast<ffi.NativeFunction<NativeReturnMinInt16>>()
+    .asFunction();
+
+typedef NativeReturnMinInt32 = ffi.Int32 Function();
+int Function() returnMinInt32 = ffiTestFunctions
+    .lookup("ReturnMinInt32")
+    .cast<ffi.NativeFunction<NativeReturnMinInt32>>()
+    .asFunction();
+
+typedef NativeTakeMaxUint8 = ffi.IntPtr Function(ffi.Uint8);
+int Function(int) takeMaxUint8 = ffiTestFunctions
+    .lookup("TakeMaxUint8")
+    .cast<ffi.NativeFunction<NativeTakeMaxUint8>>()
+    .asFunction();
+
+typedef NativeTakeMaxUint16 = ffi.IntPtr Function(ffi.Uint16);
+int Function(int) takeMaxUint16 = ffiTestFunctions
+    .lookup("TakeMaxUint16")
+    .cast<ffi.NativeFunction<NativeTakeMaxUint16>>()
+    .asFunction();
+
+typedef NativeTakeMaxUint32 = ffi.IntPtr Function(ffi.Uint32);
+int Function(int) takeMaxUint32 = ffiTestFunctions
+    .lookup("TakeMaxUint32")
+    .cast<ffi.NativeFunction<NativeTakeMaxUint32>>()
+    .asFunction();
+
+typedef NativeTakeMinInt8 = ffi.IntPtr Function(ffi.Int8);
+int Function(int) takeMinInt8 = ffiTestFunctions
+    .lookup("TakeMinInt8")
+    .cast<ffi.NativeFunction<NativeTakeMinInt8>>()
+    .asFunction();
+
+typedef NativeTakeMinInt16 = ffi.IntPtr Function(ffi.Int16);
+int Function(int) takeMinInt16 = ffiTestFunctions
+    .lookup("TakeMinInt16")
+    .cast<ffi.NativeFunction<NativeTakeMinInt16>>()
+    .asFunction();
+
+typedef NativeTakeMinInt32 = ffi.IntPtr Function(ffi.Int32);
+int Function(int) takeMinInt32 = ffiTestFunctions
+    .lookup("TakeMinInt32")
+    .cast<ffi.NativeFunction<NativeTakeMinInt32>>()
+    .asFunction();
+
+typedef NativeQuadOpSigned = ffi.Int64 Function(
+    ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
+typedef QuadOp = int Function(int, int, int, int);
+typedef IntComputationType = ffi.Int64 Function(
+    ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
+QuadOp intComputation = ffiTestFunctions
+    .lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
+
+typedef NativeQuadOpUnsigned = ffi.Uint64 Function(
+    ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
+typedef UintComputationType = ffi.Uint64 Function(
+    ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
+QuadOp uintComputation = ffiTestFunctions
+    .lookupFunction<NativeQuadOpUnsigned, QuadOp>("UintComputation");
+
+typedef DoubleUnaryOp = double Function(double);
+typedef NativeDoubleUnaryOp = ffi.Double Function(ffi.Double);
+DoubleUnaryOp times1_337Double = ffiTestFunctions
+    .lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
+
+typedef NativeFloatUnaryOp = ffi.Float Function(ffi.Float);
+DoubleUnaryOp times1_337Float = ffiTestFunctions
+    .lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
+
+typedef DecenaryOp = int Function(
+    int, int, int, int, int, int, int, int, int, int);
+typedef NativeDecenaryOp = ffi.IntPtr Function(
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr);
+DecenaryOp sumManyInts = ffiTestFunctions
+    .lookupFunction<NativeDecenaryOp, DecenaryOp>("SumManyInts");
+
+UndenaryOp sumManyIntsOdd = ffiTestFunctions
+    .lookupFunction<NativeUndenaryOp, UndenaryOp>("SumManyIntsOdd");
+
+typedef NativeDoubleDecenaryOp = ffi.Double Function(
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double,
+    ffi.Double);
+typedef DoubleDecenaryOp = double Function(double, double, double, double,
+    double, double, double, double, double, double);
+DoubleDecenaryOp sumManyDoubles = ffiTestFunctions
+    .lookupFunction<NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
+
+typedef NativeVigesimalOp = ffi.Double Function(
+    ffi.IntPtr,
+    ffi.Float,
+    ffi.IntPtr,
+    ffi.Double,
+    ffi.IntPtr,
+    ffi.Float,
+    ffi.IntPtr,
+    ffi.Double,
+    ffi.IntPtr,
+    ffi.Float,
+    ffi.IntPtr,
+    ffi.Double,
+    ffi.IntPtr,
+    ffi.Float,
+    ffi.IntPtr,
+    ffi.Double,
+    ffi.IntPtr,
+    ffi.Float,
+    ffi.IntPtr,
+    ffi.Double);
+typedef VigesimalOp = double Function(
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double,
+    int,
+    double);
+VigesimalOp sumManyNumbers = ffiTestFunctions
+    .lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
+
+typedef NativeSenaryOp = ffi.Int64 Function(
+    ffi.Int8, ffi.Int16, ffi.Int32, ffi.Uint8, ffi.Uint16, ffi.Uint32);
+typedef SenaryOp = int Function(int, int, int, int, int, int);
+SenaryOp sumSmallNumbers = ffiTestFunctions
+    .lookupFunction<NativeSenaryOp, SenaryOp>("SumSmallNumbers");
+
+typedef NativeFloatPointerToBool = ffi.Uint8 Function(ffi.Pointer<ffi.Float>);
+typedef FloatPointerToBool = int Function(ffi.Pointer<ffi.Float>);
+FloatPointerToBool isRoughly1337 = ffiTestFunctions.lookupFunction<
+    NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
+
+typedef NativeVoidToFloat = ffi.Float Function();
+typedef VoidToDouble = double Function();
+VoidToDouble inventFloatValue = ffiTestFunctions
+    .lookupFunction<NativeVoidToFloat, VoidToDouble>("InventFloatValue");
+
+typedef NullaryOp = int Function();
+typedef NativeNullaryOp64 = ffi.Int64 Function();
+final minInt64 =
+    ffiTestFunctions.lookupFunction<NativeNullaryOp64, NullaryOp>("MinInt64");
+
+typedef NativeNullaryOp32 = ffi.Int32 Function();
+final minInt32 =
+    ffiTestFunctions.lookupFunction<NativeNullaryOp32, NullaryOp>("MinInt32");
+
+typedef NativeNullaryOpDouble = ffi.Double Function();
+typedef NullaryOpDbl = double Function();
+final smallDouble = ffiTestFunctions
+    .lookupFunction<NativeNullaryOpDouble, NullaryOpDbl>("SmallDouble");
+
+typedef NativeUndenaryOp = ffi.IntPtr Function(
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr,
+    ffi.IntPtr);
+typedef UndenaryOp = int Function(
+    int, int, int, int, int, int, int, int, int, int, int);
+final regress37069 = ffiTestFunctions
+    .lookupFunction<NativeUndenaryOp, UndenaryOp>("Regress37069");
+""";
+}
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index 6311961..e5cce1d 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:convert';
 import 'dart:io';
 import 'dart:isolate';
 import 'dart:math';
@@ -29,7 +28,7 @@
 /// Command runner.
 TestResult runCommand(List<String> cmd, Map<String, String> env) {
   ProcessResult res = Process.runSync(
-      'timeout', ['-s', '$sigkill', '$timeout'] + cmd,
+      'timeout', ['-s', '$sigkill', '$timeout', ...cmd],
       environment: env);
   if (debug) {
     print('\nrunning $cmd yields:\n'
@@ -44,7 +43,7 @@
   String description;
 
   // Factory.
-  static TestRunner getTestRunner(String mode, bool ffi, String top, String tmp,
+  static TestRunner getTestRunner(String mode, String top, String tmp,
       Map<String, String> env, String fileName, Random rand) {
     String prefix = mode.substring(0, 3).toUpperCase();
     String tag = getTag(mode);
@@ -79,18 +78,21 @@
         prefix += '-NOINTRINSIFY';
         extraFlags += ['--intrinsify=false'];
       } else if (r == 2) {
-        prefix += '-COMPACTEVERY';
-        extraFlags += ['--gc_every=1000', '--use_compactor=true'];
+        final freq = rand.nextInt(1000) + 500;
+        prefix += '-COMPACTEVERY-${freq}';
+        extraFlags += ['--gc_every=${freq}', '--use_compactor=true'];
       } else if (r == 3) {
-        prefix += '-MARKSWEEPEVERY';
-        extraFlags += ['--gc_every=1000', '--use_compactor=false'];
+        final freq = rand.nextInt(1000) + 500;
+        prefix += '-MARKSWEEPEVERY-${freq}';
+        extraFlags += ['--gc_every=${freq}', '--use_compactor=false'];
       } else if (r == 4) {
-        prefix += '-DEPOPTEVERY';
-        extraFlags += ['--deoptimize_every=100'];
-      } else if (r == 5 && !ffi) {
-        // TODO: https://github.com/dart-lang/sdk/issues/37606
-        prefix += '-STACKTRACEEVERY';
-        extraFlags += ['--stacktrace_every=100'];
+        final freq = rand.nextInt(100) + 50;
+        prefix += '-DEPOPTEVERY-${freq}';
+        extraFlags += ['--deoptimize_every=${freq}'];
+      } else if (r == 5) {
+        final freq = rand.nextInt(100) + 50;
+        prefix += '-STACKTRACEEVERY-${freq}';
+        extraFlags += ['--stacktrace_every=${freq}'];
       } else if (r == 6) {
         prefix += '-OPTCOUNTER';
         extraFlags += ['--optimization_counter_threshold=1'];
@@ -106,18 +108,26 @@
       prefix += '-O3';
       extraFlags += ['--optimization_level=3'];
     }
+    // Every once in a while, use the slowpath flag.
+    if (!mode.startsWith('djs') && rand.nextInt(4) == 0) {
+      prefix += '-SLOWPATH';
+      extraFlags += ['--use-slow-path'];
+    }
+    // Every once in a while, use the deterministic flag.
+    if (!mode.startsWith('djs') && rand.nextInt(4) == 0) {
+      prefix += '-DET';
+      extraFlags += ['--deterministic'];
+    }
     // Construct runner.
     if (mode.startsWith('jit')) {
-      return new TestRunnerJIT(
-          prefix, tag, top, tmp, env, fileName, extraFlags);
+      return TestRunnerJIT(prefix, tag, top, tmp, env, fileName, extraFlags);
     } else if (mode.startsWith('aot')) {
-      return new TestRunnerAOT(
-          prefix, tag, top, tmp, env, fileName, extraFlags);
+      return TestRunnerAOT(prefix, tag, top, tmp, env, fileName, extraFlags);
     } else if (mode.startsWith('kbc')) {
-      return new TestRunnerKBC(
+      return TestRunnerKBC(
           prefix, tag, top, tmp, env, fileName, extraFlags, kbcSrc);
     } else if (mode.startsWith('djs')) {
-      return new TestRunnerDJS(prefix, tag, top, tmp, env, fileName);
+      return TestRunnerDJS(prefix, tag, top, tmp, env, fileName);
     }
     throw ('unknown runner in mode: $mode');
   }
@@ -138,6 +148,9 @@
     if (mode.endsWith('dbc64')) return 'ReleaseSIMDBC64';
     throw ('unknown tag in mode: $mode');
   }
+
+  // Print steps to reproduce build and run.
+  void printReproductionCommand();
 }
 
 /// Concrete test runner of Dart JIT.
@@ -146,13 +159,15 @@
       this.fileName, List<String> extraFlags) {
     description = '$prefix-$tag';
     dart = '$top/out/$tag/dart';
-    cmd = [dart, "--deterministic"] + extraFlags + [fileName];
+    cmd = [dart, ...extraFlags, fileName];
   }
 
   TestResult run() {
     return runCommand(cmd, env);
   }
 
+  void printReproductionCommand() => print(cmd.join(" "));
+
   String description;
   String dart;
   String fileName;
@@ -170,23 +185,30 @@
     snapshot = '$tmp/snapshot';
     env = Map<String, String>.from(e);
     env['DART_CONFIGURATION'] = tag;
-    env['OPTIONS'] = extraFlags.join(' ');
+    cmd = [precompiler, ...extraFlags, fileName, snapshot];
   }
 
   TestResult run() {
-    TestResult result = runCommand([precompiler, fileName, snapshot], env);
+    TestResult result = runCommand(cmd, env);
     if (result.exitCode != 0) {
       return result;
     }
     return runCommand([dart, snapshot], env);
   }
 
+  void printReproductionCommand() {
+    print(
+        ["DART_CONFIGURATION=${env['DART_CONFIGURATION']}", ...cmd].join(" "));
+    print([dart, snapshot].join(" "));
+  }
+
   String description;
   String precompiler;
   String dart;
   String fileName;
   String snapshot;
   Map<String, String> env;
+  List<String> cmd;
 }
 
 /// Concrete test runner of bytecode.
@@ -196,12 +218,12 @@
     description = '$prefix-$tag';
     dart = '$top/out/$tag/dart';
     if (kbcSrc) {
-      cmd = [dart] + extraFlags + [fileName];
+      cmd = [dart, ...extraFlags, fileName];
     } else {
       generate = '$top/pkg/vm/tool/gen_kernel';
       platform = '--platform=$top/out/$tag/vm_platform_strong.dill';
       dill = '$tmp/out.dill';
-      cmd = [dart] + extraFlags + [dill];
+      cmd = [dart, ...extraFlags, dill];
     }
   }
 
@@ -216,6 +238,12 @@
     return runCommand(cmd, env);
   }
 
+  void printReproductionCommand() {
+    print(
+        [generate, '--gen-bytecode', platform, '-o', dill, fileName].join(" "));
+    print(cmd.join(" "));
+  }
+
   String description;
   String generate;
   String platform;
@@ -243,6 +271,11 @@
     return runCommand(['nodejs', js], env);
   }
 
+  void printReproductionCommand() {
+    print([dart2js, fileName, '-o', js].join(" "));
+    print(['nodejs', js].join(" "));
+  }
+
   String description;
   String dart2js;
   String fileName;
@@ -286,28 +319,32 @@
   }
 
   void setup() {
-    rand = new Random();
+    rand = Random();
     tmpDir = Directory.systemTemp.createTempSync('dart_fuzz');
     fileName = '${tmpDir.path}/fuzz.dart';
+    // Testcase generation flags.
+    // Necessary To avoid false divergences between 64 and 32 bit versions.
     fp = samePrecision(mode1, mode2);
-    ffi = ffiCapable(mode1, mode2);
-    runner1 = TestRunner.getTestRunner(
-        mode1, ffi, top, tmpDir.path, env, fileName, rand);
-    runner2 = TestRunner.getTestRunner(
-        mode2, ffi, top, tmpDir.path, env, fileName, rand);
+    // Occasionally test FFI.
+    ffi = ffiCapable(mode1, mode2) && (rand.nextInt(5) == 0);
+    runner1 =
+        TestRunner.getTestRunner(mode1, top, tmpDir.path, env, fileName, rand);
+    runner2 =
+        TestRunner.getTestRunner(mode2, top, tmpDir.path, env, fileName, rand);
     isolate =
         'Isolate (${tmpDir.path}) ${ffi ? "" : "NO-"}FFI ${fp ? "" : "NO-"}FP : '
         '${runner1.description} - ${runner2.description}';
 
-    start_time = new DateTime.now().millisecondsSinceEpoch;
+    start_time = DateTime.now().millisecondsSinceEpoch;
     current_time = start_time;
     report_time = start_time;
     end_time = start_time + max(0, time - timeout) * 1000;
 
     numTests = 0;
     numSuccess = 0;
-    numNotRun = 0;
-    numTimeOut = 0;
+    numSkipped = 0;
+    numRerun = 0;
+    numTimeout = 0;
     numDivergences = 0;
   }
 
@@ -321,7 +358,7 @@
 
   bool timeIsUp() {
     if (time > 0) {
-      current_time = new DateTime.now().millisecondsSinceEpoch;
+      current_time = DateTime.now().millisecondsSinceEpoch;
       if (current_time > end_time) {
         return true;
       }
@@ -340,28 +377,36 @@
   }
 
   void showStatistics() {
-    stdout.write('\rTests: $numTests Success: $numSuccess Not-Run: '
-        '$numNotRun: Time-Out: $numTimeOut Divergences: $numDivergences');
+    stdout.write('\rTests: $numTests Success: $numSuccess (Rerun: $numRerun) '
+        'Skipped: $numSkipped Timeout: $numTimeout '
+        'Divergences: $numDivergences');
   }
 
   void generateTest() {
-    final file = new File(fileName).openSync(mode: FileMode.write);
-    new DartFuzz(seed, fp, ffi, file).run();
+    final file = File(fileName).openSync(mode: FileMode.write);
+    DartFuzz(seed, fp, ffi, file).run();
     file.closeSync();
   }
 
   void runTest() {
     TestResult result1 = runner1.run();
     TestResult result2 = runner2.run();
-    if (checkDivergence(result1, result2) == ReportStatus.rerun && rerun) {
+    var report = checkDivergence(result1, result2);
+    if (report == ReportStatus.rerun && rerun) {
       print("\nCommencing re-run .... \n");
       numDivergences--;
       result1 = runner1.run();
       result2 = runner2.run();
-      if (checkDivergence(result1, result2) == ReportStatus.no_divergence) {
+      report = checkDivergence(result1, result2);
+      if (report == ReportStatus.no_divergence) {
         print("\nNo error on re-run\n");
+        numRerun++;
       }
     }
+    if (report == ReportStatus.reported ||
+        (!rerun && report == ReportStatus.rerun)) {
+      showReproduce();
+    }
   }
 
   ReportStatus checkDivergence(TestResult result1, TestResult result2) {
@@ -379,11 +424,11 @@
           break;
         case -sigkill:
           // Both had a time out.
-          numTimeOut++;
+          numTimeout++;
           break;
         default:
           // Both had an error.
-          numNotRun++;
+          numSkipped++;
           break;
       }
     } else {
@@ -392,7 +437,7 @@
         // When only true divergences are requested, any divergence
         // with at least one time out is treated as a regular time out.
         if (result1.exitCode == -sigkill || result2.exitCode == -sigkill) {
-          numTimeOut++;
+          numTimeout++;
           return ReportStatus.ignored;
         }
       }
@@ -438,6 +483,17 @@
     }
   }
 
+  void showReproduce() {
+    print("\n-- BEGIN REPRODUCE  --\n");
+    print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp"
+        "--seed ${seed} $fileName");
+    print("\n-- RUN 1 --\n");
+    runner1.printReproductionCommand();
+    print("\n-- RUN 2 --\n");
+    runner2.printReproductionCommand();
+    print("\n-- END REPRODUCE  --\n");
+  }
+
   // Context.
   final Map<String, String> env;
   final int repeat;
@@ -469,8 +525,9 @@
   // Stats.
   int numTests;
   int numSuccess;
-  int numNotRun;
-  int numTimeOut;
+  int numSkipped;
+  int numRerun;
+  int numTimeout;
   int numDivergences;
 }
 
@@ -486,7 +543,7 @@
       this.mode1,
       this.mode2,
       this.rerun)
-      : top = getTop(tp) {}
+      : top = getTop(tp);
 
   start() async {
     print('\n**\n**** Dart Fuzz Testing Session\n**\n');
@@ -502,9 +559,9 @@
     print('Show Stats      : ${showStats}');
     print('Dart Dev        : ${top}');
     // Fork.
-    List<ReceivePort> ports = new List();
+    List<ReceivePort> ports = List();
     for (int i = 0; i < isolates; i++) {
-      ReceivePort r = new ReceivePort();
+      ReceivePort r = ReceivePort();
       ports.add(r);
       port = r.sendPort;
       await Isolate.spawn(run, this);
@@ -528,7 +585,7 @@
     try {
       final m1 = getMode(session.mode1, null);
       final m2 = getMode(session.mode2, m1);
-      final fuzz = new DartFuzzTest(
+      final fuzz = DartFuzzTest(
           Platform.environment,
           session.repeat,
           session.time,
@@ -561,7 +618,7 @@
     // Random when not set.
     if (mode == null || mode == '') {
       // Pick a mode at random (cluster), different from other.
-      Random rand = new Random();
+      Random rand = Random();
       do {
         mode = clusterModes[rand.nextInt(clusterModes.length)];
       } while (mode == other);
@@ -648,7 +705,7 @@
 /// Main driver for a fuzz testing session.
 main(List<String> arguments) {
   // Set up argument parser.
-  final parser = new ArgParser()
+  final parser = ArgParser()
     ..addOption('isolates', help: 'number of isolates to use', defaultsTo: '1')
     ..addOption('repeat', help: 'number of tests to run', defaultsTo: '1000')
     ..addOption('time', help: 'time limit in seconds', defaultsTo: '0')
@@ -680,7 +737,7 @@
     if (shards > 1) {
       print('\nSHARD $shard OF $shards');
     }
-    new DartFuzzTestSession(
+    DartFuzzTestSession(
             int.parse(results['isolates']),
             int.parse(results['repeat']),
             int.parse(results['time']),
diff --git a/runtime/tools/dartfuzz/dartfuzz_values.dart b/runtime/tools/dartfuzz/dartfuzz_values.dart
index 9849cf6..7886ae6 100644
--- a/runtime/tools/dartfuzz/dartfuzz_values.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_values.dart
@@ -11,14 +11,14 @@
 
   const DartType._withName(this.name);
 
-  static const VOID = const DartType._withName('void');
-  static const BOOL = const DartType._withName('bool');
-  static const INT = const DartType._withName('int');
-  static const DOUBLE = const DartType._withName('double');
-  static const STRING = const DartType._withName('String');
-  static const INT_LIST = const DartType._withName('List<int>');
-  static const INT_SET = const DartType._withName('Set<int>');
-  static const INT_STRING_MAP = const DartType._withName('Map<int, String>');
+  static const VOID = DartType._withName('void');
+  static const BOOL = DartType._withName('bool');
+  static const INT = DartType._withName('int');
+  static const DOUBLE = DartType._withName('double');
+  static const STRING = DartType._withName('String');
+  static const INT_LIST = DartType._withName('List<int>');
+  static const INT_SET = DartType._withName('Set<int>');
+  static const INT_STRING_MAP = DartType._withName('Map<int, String>');
 
   // All value types.
   static const allTypes = [
diff --git a/runtime/tools/dartfuzz/gen_api_table.dart b/runtime/tools/dartfuzz/gen_api_table.dart
index 4842ff0..1231006 100644
--- a/runtime/tools/dartfuzz/gen_api_table.dart
+++ b/runtime/tools/dartfuzz/gen_api_table.dart
@@ -14,9 +14,8 @@
 
 import 'dart:io';
 
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
@@ -31,35 +30,35 @@
 }
 
 // Lists of recognized methods, organized by return type.
-var boolTable = List<DartLib>();
-var intTable = List<DartLib>();
-var doubleTable = List<DartLib>();
-var stringTable = List<DartLib>();
-var listTable = List<DartLib>();
-var setTable = List<DartLib>();
-var mapTable = List<DartLib>();
+var boolTable = <DartLib>[];
+var intTable = <DartLib>[];
+var doubleTable = <DartLib>[];
+var stringTable = <DartLib>[];
+var listTable = <DartLib>[];
+var setTable = <DartLib>[];
+var mapTable = <DartLib>[];
 
 main() async {
   // Set paths. Note that for this particular use case, packageRoot can be
   // any directory. Here, we set it to the top of the SDK development, and
   // derive the required sdkPath from there.
-  String packageRoot = Platform.environment['DART_TOP'];
+  final String packageRoot = Platform.environment['DART_TOP'];
   if (packageRoot == null) {
-    throw new StateError('No environment variable DART_TOP');
+    throw StateError('No environment variable DART_TOP');
   }
-  String sdkPath = '$packageRoot/tools/sdks/dart-sdk';
+  final sdkPath = '$packageRoot/tools/sdks/dart-sdk';
 
   // This does most of the hard work of getting the analyzer configured
   // correctly. Typically the included paths are the files and directories
   // that need to be analyzed, but the SDK is always available, so it isn't
   // really important for this particular use case. We use the implementation
   // class in order to pass in the sdkPath directly.
-  PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
-  AnalysisContextCollection collection = new AnalysisContextCollectionImpl(
+  final provider = PhysicalResourceProvider.INSTANCE;
+  final collection = AnalysisContextCollectionImpl(
       includedPaths: <String>[packageRoot],
       resourceProvider: provider,
       sdkPath: sdkPath);
-  AnalysisSession session = collection.contexts[0].currentSession;
+  final AnalysisSession session = collection.contexts[0].currentSession;
 
   // Visit libraries for table generation.
   await visitLibraryAtUri(session, 'dart:async');
@@ -85,10 +84,10 @@
 }
 
 visitLibraryAtUri(AnalysisSession session, String uri) async {
-  String libPath = session.uriConverter.uriToPath(Uri.parse(uri));
+  final String libPath = session.uriConverter.uriToPath(Uri.parse(uri));
   ResolvedLibraryResult result = await session.getResolvedLibrary(libPath);
   if (result.state != ResultState.VALID) {
-    throw new StateError('Unable to resolve "$uri"');
+    throw StateError('Unable to resolve "$uri"');
   }
   visitLibrary(result.element);
 }
@@ -140,7 +139,7 @@
   for (ConstructorElement constructor in classElement.constructors) {
     if (constructor.isPublic &&
         constructor.isFactory &&
-        !constructor.name.isEmpty) {
+        constructor.name.isNotEmpty) {
       addToTable(
           typeString(classElement.type),
           '${classElement.name}.${constructor.name}',
@@ -244,6 +243,8 @@
       return setTable;
     case 'M':
       return mapTable;
+    default:
+      throw ArgumentError('Invalid ret value: $ret');
   }
 }
 
diff --git a/runtime/tools/dartfuzz/pubspec.yaml b/runtime/tools/dartfuzz/pubspec.yaml
new file mode 100644
index 0000000..1e5277e
--- /dev/null
+++ b/runtime/tools/dartfuzz/pubspec.yaml
@@ -0,0 +1,7 @@
+name: dartfuzz
+
+environment:
+  sdk: '>=2.2.2 <3.0.0'
+
+dev_dependencies:
+  pedantic: 'any'
diff --git a/runtime/tools/run_clang_tidy.dart b/runtime/tools/run_clang_tidy.dart
new file mode 100644
index 0000000..d165e77
--- /dev/null
+++ b/runtime/tools/run_clang_tidy.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:math';
+
+import 'package:pool/pool.dart';
+
+const String clangTidy = './buildtools/linux-x64/clang/bin/clang-tidy';
+
+List<String> compilerFlagsForFile(String filepath) {
+  final flags = <String>[
+    '-Iruntime',
+    '-Ithird_party',
+    '-Iruntime/include',
+    '-Ithird_party/tcmalloc/gperftools/src',
+    '-Ithird_party/boringssl/src/include',
+    '-Ithird_party/zlib',
+    '-DTARGET_ARCH_X64',
+    '-DDEBUG',
+    '-DTARGET_OS_LINUX',
+    '-DTESTING',
+    '-x',
+    'c++',
+  ];
+  return flags;
+}
+
+Future<ProcessResult> runClangTidyOn(String filepath) async {
+  // The `runtime/.clang-tidy` file has the enabled checks in it.
+  final args = <String>['-quiet', filepath, '--']
+    ..addAll(compilerFlagsForFile(filepath));
+  return await Process.run(clangTidy, args);
+}
+
+final pool = new Pool(max(1, Platform.numberOfProcessors ~/ 2));
+
+// Exclude running the linter on those files.
+final Set<String> excludedFiles = Set<String>.from([
+  // These files are not valid cc files but rather cc templates
+  'runtime/bin/abi_version_in.cc',
+  'runtime/bin/builtin_in.cc',
+  'runtime/bin/snapshot_in.cc',
+  'runtime/lib/libgen_in.cc',
+  'runtime/vm/version_in.cc',
+
+  // These files cannot be analyzed by itself (must be included indirectly).
+  'runtime/bin/android.h',
+  'runtime/bin/eventhandler_android.h',
+  'runtime/bin/eventhandler_fuchsia.h',
+  'runtime/bin/eventhandler_linux.h',
+  'runtime/bin/eventhandler_macos.h',
+  'runtime/bin/eventhandler_win.h',
+  'runtime/bin/namespace_android.h',
+  'runtime/bin/namespace_fuchsia.h',
+  'runtime/bin/namespace_linux.h',
+  'runtime/bin/namespace_macos.h',
+  'runtime/bin/namespace_win.h',
+  'runtime/bin/socket_base_android.h',
+  'runtime/bin/socket_base_fuchsia.h',
+  'runtime/bin/socket_base_linux.h',
+  'runtime/bin/socket_base_macos.h',
+  'runtime/bin/socket_base_win.h',
+  'runtime/bin/thread_android.h',
+  'runtime/bin/thread_fuchsia.h',
+  'runtime/bin/thread_linux.h',
+  'runtime/bin/thread_macos.h',
+  'runtime/bin/thread_win.h',
+  'runtime/platform/atomic_android.h',
+  'runtime/platform/atomic_fuchsia.h',
+  'runtime/platform/atomic_linux.h',
+  'runtime/platform/atomic_macos.h',
+  'runtime/platform/atomic_win.h',
+  'runtime/platform/utils_android.h',
+  'runtime/platform/utils_fuchsia.h',
+  'runtime/platform/utils_linux.h',
+  'runtime/platform/utils_macos.h',
+  'runtime/platform/utils_win.h',
+  'runtime/vm/compiler/assembler/assembler_arm64.h',
+  'runtime/vm/compiler/assembler/assembler_arm.h',
+  'runtime/vm/compiler/assembler/assembler_dbc.h',
+  'runtime/vm/compiler/assembler/assembler_ia32.h',
+  'runtime/vm/compiler/assembler/assembler_x64.h',
+  'runtime/vm/compiler/runtime_offsets_extracted.h',
+  'runtime/vm/constants_arm64.h',
+  'runtime/vm/constants_arm.h',
+  'runtime/vm/constants_dbc.h',
+  'runtime/vm/constants_ia32.h',
+  'runtime/vm/constants_x64.h',
+  'runtime/vm/cpu_arm64.h',
+  'runtime/vm/cpu_arm.h',
+  'runtime/vm/cpu_dbc.h',
+  'runtime/vm/cpu_ia32.h',
+  'runtime/vm/cpu_x64.h',
+  'runtime/vm/instructions_arm64.h',
+  'runtime/vm/instructions_arm.h',
+  'runtime/vm/instructions_dbc.h',
+  'runtime/vm/instructions_ia32.h',
+  'runtime/vm/instructions_x64.h',
+  'runtime/vm/os_thread_android.h',
+  'runtime/vm/os_thread_fuchsia.h',
+  'runtime/vm/os_thread_linux.h',
+  'runtime/vm/os_thread_macos.h',
+  'runtime/vm/os_thread_win.h',
+  'runtime/vm/regexp_assembler_bytecode_inl.h',
+  'runtime/vm/simulator_arm64.h',
+  'runtime/vm/simulator_arm.h',
+  'runtime/vm/simulator_dbc.h',
+  'runtime/vm/stack_frame_arm64.h',
+  'runtime/vm/stack_frame_arm.h',
+  'runtime/vm/stack_frame_dbc.h',
+  'runtime/vm/stack_frame_ia32.h',
+  'runtime/vm/stack_frame_x64.h',
+
+  // By default the gclient checkout doesn't have llvm pulled in.
+  'runtime/llvm_codegen/bit/bit.h',
+  'runtime/llvm_codegen/bit/main.cc',
+  'runtime/llvm_codegen/bit/test.cc',
+  'runtime/llvm_codegen/codegen/main.cc',
+
+  // Only available in special builds
+  'runtime/bin/io_service_no_ssl.h',
+  'runtime/bin/utils_win.h',
+  'runtime/vm/compiler/backend/locations_helpers_arm.h',
+]);
+
+main(List<String> files) async {
+  bool isFirstFailure = true;
+
+  files = files.where((filepath) => !excludedFiles.contains(filepath)).toList();
+
+  // Analyze the [files] in parallel.
+  await Future.wait(files.map((String filepath) async {
+    final processResult =
+        await pool.withResource(() => runClangTidyOn(filepath));
+
+    final int exitCode = processResult.exitCode;
+    final String stdout = processResult.stdout.trim();
+    final String stderr = processResult.stderr.trim();
+
+    if (exitCode != 0 || stdout.isNotEmpty) {
+      if (!isFirstFailure) {
+        print('');
+        print('--------------------------------------------------------------');
+        print('');
+      }
+      isFirstFailure = false;
+    }
+
+    if (exitCode != 0) {
+      print('exit-code: $exitCode');
+      print('stdout:');
+      print('${stdout}');
+      print('stderr:');
+      print('${stderr}');
+    } else if (stdout.isNotEmpty) {
+      // The actual lints go to stdout.
+      print(stdout);
+    }
+  }));
+}
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 6b9f82f..a526aec 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -16,6 +16,7 @@
 import("../../sdk/lib/profiler/profiler_sources.gni")
 import("../../sdk/lib/typed_data/typed_data_sources.gni")
 import("../../sdk/lib/vmservice/vmservice_sources.gni")
+import("../../sdk/lib/wasm/wasm_sources.gni")
 import("../../utils/compile_platform.gni")
 import("../bin/cli_sources.gni")
 import("../bin/io_sources.gni")
@@ -33,6 +34,7 @@
 import("../lib/profiler_sources.gni")
 import("../lib/typed_data_sources.gni")
 import("../lib/vmservice_sources.gni")
+import("../lib/wasm_sources.gni")
 import("../runtime_args.gni")
 import("compiler/compiler_sources.gni")
 import("heap/heap_sources.gni")
@@ -106,7 +108,7 @@
                internal_runtime_cc_files + isolate_runtime_cc_files +
                math_runtime_cc_files + mirrors_runtime_cc_files +
                typed_data_runtime_cc_files + vmservice_runtime_cc_files +
-               ffi_runtime_cc_files
+               ffi_runtime_cc_files + wasm_runtime_cc_files
   sources = [ "bootstrap.cc" ] + rebase_path(allsources, ".", "../lib")
   snapshot_sources = []
   nosnapshot_sources = []
@@ -140,24 +142,13 @@
     if (defined(invoker.exclude_source) && invoker.exclude_source) {
       args += [ "--exclude-source" ]
     }
-    if (defined(invoker.legacy) && invoker.legacy) {
-      args += [ "--legacy-mode" ]
-      outline = "vm_outline_strong.dill"
-    } else {
-      outline = "vm_outline" + output_postfix + ".dill"
-    }
+    outline = "vm_outline" + output_postfix + ".dill"
     if (dart_platform_bytecode) {
       args += [ "--bytecode" ]
     }
   }
 }
 
-gen_vm_platform("vm_legacy_platform") {
-  exclude_source = false
-  legacy = true
-  output_postfix = ""
-}
-
 gen_vm_platform("vm_platform") {
   add_implicit_vm_platform_dependency = false
   exclude_source = false
@@ -172,7 +163,6 @@
 
 group("kernel_platform_files") {
   public_deps = [
-    ":vm_legacy_platform",
     ":vm_platform",
     ":vm_platform_stripped",
   ]
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index a95642a..db49703 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -511,25 +511,13 @@
   return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
 }
 
-BENCHMARK_SIZE(CoreSnapshotSize) {
-  const char* kScriptChars =
-      "import 'dart:async';\n"
-      "import 'dart:core';\n"
-      "import 'dart:collection';\n"
-      "import 'dart:_internal';\n"
-      "import 'dart:math';\n"
-      "import 'dart:isolate';\n"
-      "import 'dart:mirrors';\n"
-      "import 'dart:typed_data';\n"
-      "\n";
-
-  // Start an Isolate, load a script and create a full snapshot.
-  uint8_t* vm_snapshot_data_buffer;
-  uint8_t* isolate_snapshot_data_buffer;
+// Start an Isolate, load a script and create a full snapshot.
+static void BenchmarkSnapshotSize(Benchmark* benchmark, const char* script) {
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
-  TestCase::LoadCoreTestScript(kScriptChars, NULL);
+  TestCase::LoadCoreTestScript(script, nullptr);
 
+  Thread* thread = Thread::Current();
   TransitionNativeToVM transition(thread);
   StackZone zone(thread);
   HANDLESCOPE(thread);
@@ -537,58 +525,63 @@
   Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
+  uint8_t* vm_snapshot_data_buffer = nullptr;
+  uint8_t* isolate_snapshot_data_buffer = nullptr;
+  uint8_t* vm_snapshot_text_buffer = nullptr;
+  uint8_t* isolate_snapshot_text_buffer = nullptr;
+  BlobImageWriter vm_image_writer(thread, &vm_snapshot_text_buffer,
+                                  &malloc_allocator, 2 * MB /* initial_size */,
+                                  /*shared_objects=*/nullptr,
+                                  /*shared_instructions=*/nullptr,
+                                  /*reused_instructions=*/nullptr);
+  BlobImageWriter isolate_image_writer(thread, &isolate_snapshot_text_buffer,
+                                       &malloc_allocator,
+                                       2 * MB /* initial_size */,
+                                       /*shared_objects=*/nullptr,
+                                       /*shared_instructions=*/nullptr,
+                                       /*reused_instructions=*/nullptr);
   FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
                             &isolate_snapshot_data_buffer, &malloc_allocator,
-                            NULL, NULL /* image_writer */);
+                            &vm_image_writer, &isolate_image_writer);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot =
       Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
   ASSERT(snapshot->kind() == Snapshot::kFull);
-  benchmark->set_score(snapshot->length());
+  benchmark->set_score(writer.IsolateSnapshotSize() +
+                       isolate_image_writer.data_size());
 
   free(vm_snapshot_data_buffer);
+  free(vm_snapshot_text_buffer);
   free(isolate_snapshot_data_buffer);
+  free(isolate_snapshot_text_buffer);
+}
+
+BENCHMARK_SIZE(CoreSnapshotSize) {
+  BenchmarkSnapshotSize(benchmark,
+                        "import 'dart:async';\n"
+                        "import 'dart:core';\n"
+                        "import 'dart:collection';\n"
+                        "import 'dart:_internal';\n"
+                        "import 'dart:math';\n"
+                        "import 'dart:isolate';\n"
+                        "import 'dart:mirrors';\n"
+                        "import 'dart:typed_data';\n"
+                        "\n");
 }
 
 BENCHMARK_SIZE(StandaloneSnapshotSize) {
-  const char* kScriptChars =
-      "import 'dart:async';\n"
-      "import 'dart:core';\n"
-      "import 'dart:collection';\n"
-      "import 'dart:convert';\n"
-      "import 'dart:math';\n"
-      "import 'dart:isolate';\n"
-      "import 'dart:mirrors';\n"
-      "import 'dart:typed_data';\n"
-      "import 'dart:io';\n"
-      "import 'dart:cli';\n"
-      "\n";
-
-  // Start an Isolate, load a script and create a full snapshot.
-  uint8_t* vm_snapshot_data_buffer;
-  uint8_t* isolate_snapshot_data_buffer;
-  // Need to load the script into the dart: core library due to
-  // the import of dart:_internal.
-  TestCase::LoadCoreTestScript(kScriptChars, NULL);
-
-  TransitionNativeToVM transition(thread);
-  StackZone zone(thread);
-  HANDLESCOPE(thread);
-
-  Api::CheckAndFinalizePendingClasses(thread);
-
-  // Write snapshot with object content.
-  FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
-                            &isolate_snapshot_data_buffer, &malloc_allocator,
-                            NULL, NULL /* image_writer */);
-  writer.WriteFullSnapshot();
-  const Snapshot* snapshot =
-      Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
-  ASSERT(snapshot->kind() == Snapshot::kFull);
-  benchmark->set_score(snapshot->length());
-
-  free(vm_snapshot_data_buffer);
-  free(isolate_snapshot_data_buffer);
+  BenchmarkSnapshotSize(benchmark,
+                        "import 'dart:async';\n"
+                        "import 'dart:core';\n"
+                        "import 'dart:collection';\n"
+                        "import 'dart:convert';\n"
+                        "import 'dart:math';\n"
+                        "import 'dart:isolate';\n"
+                        "import 'dart:mirrors';\n"
+                        "import 'dart:typed_data';\n"
+                        "import 'dart:io';\n"
+                        "import 'dart:cli';\n"
+                        "\n");
 }
 
 BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 0cf802f..584baa3 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -60,6 +60,12 @@
     field ^= fields.At(i);
     field.set_is_unboxing_candidate(false);
   }
+  // _Closure._hash field should be explicitly marked as nullable because
+  // VM creates instances of _Closure without compiling its constructors,
+  // so it won't get nullability info from a constructor.
+  field ^= fields.At(fields.Length() - 1);
+  ASSERT(String::Handle(zone, field.UserVisibleName()).Equals("_hash"));
+  field.RecordStore(Object::null_object());
 
 #if defined(DEBUG)
   // Verify that closure field offsets are identical in Dart and C++.
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index a0e99e3..f733331 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -141,6 +141,11 @@
   ASSERT(!library.IsNull());
   library.set_native_entry_resolver(resolver);
   library.set_native_entry_symbol_resolver(symbol_resolver);
+
+  library = Library::WasmLibrary();
+  ASSERT(!library.IsNull());
+  library.set_native_entry_resolver(resolver);
+  library.set_native_entry_symbol_resolver(symbol_resolver);
 }
 
 bool Bootstrap::IsBootstrapResolver(Dart_NativeEntryResolver resolver) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 386d4fb..efccf88 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -12,6 +12,7 @@
 namespace dart {
 
 // List of bootstrap native entry points used in the core dart library.
+// V(function_name, argument_count)
 #define BOOTSTRAP_NATIVE_LIST(V)                                               \
   V(AsyncStarMoveNext_debuggerStepCheck, 1)                                    \
   V(DartAsync_fatal, 1)                                                        \
@@ -352,10 +353,6 @@
   V(WeakProperty_getValue, 1)                                                  \
   V(WeakProperty_setValue, 2)                                                  \
   V(Uri_isWindowsPlatform, 0)                                                  \
-  V(LibraryPrefix_load, 1)                                                     \
-  V(LibraryPrefix_invalidateDependentCode, 1)                                  \
-  V(LibraryPrefix_loadError, 1)                                                \
-  V(LibraryPrefix_isLoaded, 1)                                                 \
   V(UserTag_new, 2)                                                            \
   V(UserTag_label, 1)                                                          \
   V(UserTag_defaultTag, 0)                                                     \
@@ -384,7 +381,8 @@
   V(Ffi_cast, 1)                                                               \
   V(Ffi_sizeOf, 0)                                                             \
   V(Ffi_asFunctionInternal, 1)                                                 \
-  V(Ffi_fromFunction, 2)                                                       \
+  V(Ffi_nativeCallbackFunction, 2)                                             \
+  V(Ffi_pointerFromFunction, 1)                                                \
   V(Ffi_dl_open, 1)                                                            \
   V(Ffi_dl_lookup, 2)                                                          \
   V(Ffi_dl_getHandle, 1)                                                       \
@@ -392,7 +390,8 @@
   V(Ffi_dl_processLibrary, 0)                                                  \
   V(Ffi_dl_executableLibrary, 0)                                               \
   V(TransferableTypedData_factory, 2)                                          \
-  V(TransferableTypedData_materialize, 1)
+  V(TransferableTypedData_materialize, 1)                                      \
+  V(Wasm_callFunction, 2)
 
 // List of bootstrap native entry points used in the dart:mirror library.
 #define MIRRORS_BOOTSTRAP_NATIVE_LIST(V)                                       \
diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc
new file mode 100644
index 0000000..7e01696
--- /dev/null
+++ b/runtime/vm/bss_relocs.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include <vm/bss_relocs.h>
+#include <vm/runtime_entry.h>
+#include <vm/thread.h>
+
+namespace dart {
+
+void BSS::Initialize(Thread* current, uword* bss_start) {
+  bss_start[BSS::RelocationIndex(
+      BSS::Relocation::DRT_GetThreadForNativeCallback)] =
+      reinterpret_cast<uword>(DLRT_GetThreadForNativeCallback);
+}
+
+}  // namespace dart
diff --git a/runtime/vm/bss_relocs.h b/runtime/vm/bss_relocs.h
new file mode 100644
index 0000000..aa3c1f7
--- /dev/null
+++ b/runtime/vm/bss_relocs.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_BSS_RELOCS_H_
+#define RUNTIME_VM_BSS_RELOCS_H_
+
+#include <platform/allocation.h>
+
+namespace dart {
+class Thread;
+
+class BSS : public AllStatic {
+ public:
+  enum class Relocation : intptr_t {
+    DRT_GetThreadForNativeCallback = 0,
+    NumRelocations = 1
+  };
+
+  static intptr_t RelocationIndex(Relocation reloc) {
+    return static_cast<intptr_t>(reloc);
+  }
+
+  static void Initialize(Thread* current, uword* bss);
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_BSS_RELOCS_H_
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 7a33519..aa21dc9 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1241,12 +1241,6 @@
   sentinel.SetStaticValue(enum_value, true);
   sentinel.RecordStore(enum_value);
 
-  const GrowableObjectArray& pending_unevaluated_const_fields =
-      GrowableObjectArray::Handle(zone,
-                                  thread->isolate()
-                                      ->object_store()
-                                      ->pending_unevaluated_const_fields());
-
   ASSERT(enum_cls.is_declared_in_bytecode() || enum_cls.kernel_offset() > 0);
   Error& error = Error::Handle(zone);
   for (intptr_t i = 0; i < fields.Length(); i++) {
@@ -1255,20 +1249,13 @@
         (sentinel.raw() == field.raw())) {
       continue;
     }
-    // The eager evaluation of the enum values is required for hot-reload (see
-    // commit e3ecc87). However, while busy loading the constant table, we
-    // need to postpone this evaluation until table is done.
+    // Hot-reload expects the static const fields to be evaluated when
+    // performing a reload.
     if (!FLAG_precompiled_mode) {
       if (field.IsUninitialized()) {
-        if (pending_unevaluated_const_fields.IsNull()) {
-          // Evaluate right away.
-          error = field.Initialize();
-          if (!error.IsNull()) {
-            ReportError(error);
-          }
-        } else {
-          // Postpone evaluation until we have a constant table.
-          pending_unevaluated_const_fields.Add(field);
+        error = field.Initialize();
+        if (!error.IsNull()) {
+          ReportError(error);
         }
       }
     }
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 624c4bc..7a7f898 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -253,7 +253,12 @@
   if (raw_cls == NULL) {
     table_[index] = ClassAndSize(raw_cls, 0);
   } else {
-    table_[index] = ClassAndSize(raw_cls, Class::instance_size(raw_cls));
+    // Ensure we never change size for a given cid from one non-zero size to
+    // another non-zero size.
+    const intptr_t old_size = table_[index].size_;
+    const intptr_t new_size = Class::instance_size(raw_cls);
+    ASSERT(old_size == 0 || old_size == new_size);
+    table_[index] = ClassAndSize(raw_cls, new_size);
   }
 }
 
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index df677a5..3de2d46 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -193,6 +193,47 @@
   explicit ClassTable(ClassTable* original);
   ~ClassTable();
 
+  void CopyBeforeHotReload(ClassAndSize** copy, intptr_t* copy_num_cids) {
+    // The [IsolateReloadContext] will need to maintain a copy of the old class
+    // table until instances have been morphed.
+    const intptr_t bytes = sizeof(ClassAndSize) * NumCids();
+    *copy_num_cids = NumCids();
+    *copy = static_cast<ClassAndSize*>(malloc(bytes));
+    memmove(*copy, table_, bytes);
+  }
+
+  void ResetBeforeHotReload() {
+    // The [IsolateReloadContext] is now source-of-truth for GC.
+    //
+    // Though we cannot clear out the class pointers, because a hot-reload
+    // contains only a diff: If e.g. a class included in the hot-reload has a
+    // super class not included in the diff, it will look up in this class table
+    // to find the super class (e.g. `cls.SuperClass` will cause us to come
+    // here).
+    for (intptr_t i = 0; i < top_; ++i) {
+      table_[i].size_ = 0;
+    }
+  }
+
+  void ResetAfterHotReload(ClassAndSize* old_table,
+                           intptr_t num_old_cids,
+                           bool is_rollback) {
+    // The [IsolateReloadContext] is no longer source-of-truth for GC after we
+    // return, so we restore size information for all classes.
+    if (is_rollback) {
+      SetNumCids(num_old_cids);
+      memmove(table_, old_table, num_old_cids * sizeof(ClassAndSize));
+    } else {
+      CopySizesFromClassObjects();
+    }
+
+    // Can't free this table immediately as another thread (e.g., concurrent
+    // marker or sweeper) may be between loading the table pointer and loading
+    // the table element. The table will be freed at the next major GC or
+    // isolate shutdown.
+    AddOldTable(old_table);
+  }
+
   // Thread-safe.
   RawClass* At(intptr_t index) const {
     ASSERT(IsValidIndex(index));
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index dab1e6d..1939554 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -6,6 +6,7 @@
 
 #include "platform/assert.h"
 #include "vm/bootstrap.h"
+#include "vm/bss_relocs.h"
 #include "vm/class_id.h"
 #include "vm/code_observers.h"
 #include "vm/compiler/backend/code_statistics.h"
@@ -613,7 +614,7 @@
           func.SetInstructions(StubCode::InterpretCall());
         } else if (FLAG_use_bytecode_compiler && func.HasBytecode()) {
           func.SetInstructions(StubCode::LazyCompile());
-#endif                                 // !defined(DART_PRECOMPILED_RUNTIME)
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
         } else {
           func.ClearCode();  // Set code and entrypoint to lazy compile stub.
         }
@@ -800,9 +801,12 @@
       AutoTraceObject(data);
       WriteFromTo(data);
 
-      // TODO(37295): FFI callbacks shouldn't be written to a snapshot. They
-      // should only be referenced by the callback registry in Thread.
-      ASSERT(data->ptr()->callback_id_ == 0);
+      if (s->kind() == Snapshot::kFullAOT) {
+        s->WriteUnsigned(data->ptr()->callback_id_);
+      } else {
+        // FFI callbacks can only be written to AOT snapshots.
+        ASSERT(data->ptr()->callback_target_ == Object::null());
+      }
     }
   }
 
@@ -834,7 +838,8 @@
       Deserializer::InitializeHeader(data, kFfiTrampolineDataCid,
                                      FfiTrampolineData::InstanceSize());
       ReadFromTo(data);
-      data->ptr()->callback_id_ = 0;
+      data->ptr()->callback_id_ =
+          d->kind() == Snapshot::kFullAOT ? d->ReadUnsigned() : 0;
     }
   }
 };
@@ -1622,8 +1627,7 @@
       WriteFromTo(bytecode);
       s->Write<int32_t>(bytecode->ptr()->instructions_binary_offset_);
       s->Write<int32_t>(bytecode->ptr()->source_positions_binary_offset_);
-      NOT_IN_PRODUCT(
-          s->Write<int32_t>(bytecode->ptr()->local_variables_binary_offset_));
+      s->Write<int32_t>(bytecode->ptr()->local_variables_binary_offset_);
     }
   }
 
@@ -1658,8 +1662,7 @@
       ReadFromTo(bytecode);
       bytecode->ptr()->instructions_binary_offset_ = d->Read<int32_t>();
       bytecode->ptr()->source_positions_binary_offset_ = d->Read<int32_t>();
-      NOT_IN_PRODUCT(bytecode->ptr()->local_variables_binary_offset_ =
-                         d->Read<int32_t>());
+      bytecode->ptr()->local_variables_binary_offset_ = d->Read<int32_t>();
     }
   }
 
@@ -2841,7 +2844,6 @@
       ReadFromTo(prefix);
       prefix->ptr()->num_imports_ = d->Read<uint16_t>();
       prefix->ptr()->is_deferred_load_ = d->Read<bool>();
-      prefix->ptr()->is_loaded_ = !prefix->ptr()->is_deferred_load_;
     }
   }
 };
@@ -3303,19 +3305,6 @@
   }
 
   void ReadFill(Deserializer* d) {}
-
-  void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
-    const Class& mint_cls =
-        Class::Handle(zone, Isolate::Current()->object_store()->mint_class());
-    mint_cls.set_constants(Object::empty_array());
-    Object& number = Object::Handle(zone);
-    for (intptr_t i = start_index_; i < stop_index_; i++) {
-      number = refs.At(i);
-      if (number.IsMint() && number.IsCanonical()) {
-        mint_cls.InsertCanonicalMint(zone, Mint::Cast(number));
-      }
-    }
-  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4097,159 +4086,6 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-class OneByteStringSerializationCluster : public SerializationCluster {
- public:
-  OneByteStringSerializationCluster() : SerializationCluster("OneByteString") {}
-  ~OneByteStringSerializationCluster() {}
-
-  void Trace(Serializer* s, RawObject* object) {
-    RawOneByteString* str = reinterpret_cast<RawOneByteString*>(object);
-    objects_.Add(str);
-  }
-
-  void WriteAlloc(Serializer* s) {
-    s->WriteCid(kOneByteStringCid);
-    intptr_t count = objects_.length();
-    s->WriteUnsigned(count);
-    for (intptr_t i = 0; i < count; i++) {
-      RawOneByteString* str = objects_[i];
-      s->AssignRef(str);
-      AutoTraceObject(str);
-      intptr_t length = Smi::Value(str->ptr()->length_);
-      s->WriteUnsigned(length);
-    }
-  }
-
-  void WriteFill(Serializer* s) {
-    intptr_t count = objects_.length();
-    for (intptr_t i = 0; i < count; i++) {
-      RawOneByteString* str = objects_[i];
-      AutoTraceObject(str);
-      intptr_t length = Smi::Value(str->ptr()->length_);
-      s->WriteUnsigned(length);
-      s->Write<bool>(str->IsCanonical());
-      intptr_t hash = String::GetCachedHash(str);
-      s->Write<int32_t>(hash);
-      s->WriteBytes(str->ptr()->data(), length);
-    }
-  }
-
- private:
-  GrowableArray<RawOneByteString*> objects_;
-};
-#endif  // !DART_PRECOMPILED_RUNTIME
-
-class OneByteStringDeserializationCluster : public DeserializationCluster {
- public:
-  OneByteStringDeserializationCluster() {}
-  ~OneByteStringDeserializationCluster() {}
-
-  void ReadAlloc(Deserializer* d) {
-    start_index_ = d->next_index();
-    PageSpace* old_space = d->heap()->old_space();
-    intptr_t count = d->ReadUnsigned();
-    for (intptr_t i = 0; i < count; i++) {
-      intptr_t length = d->ReadUnsigned();
-      d->AssignRef(AllocateUninitialized(old_space,
-                                         OneByteString::InstanceSize(length)));
-    }
-    stop_index_ = d->next_index();
-  }
-
-  void ReadFill(Deserializer* d) {
-    for (intptr_t id = start_index_; id < stop_index_; id++) {
-      RawOneByteString* str = reinterpret_cast<RawOneByteString*>(d->Ref(id));
-      intptr_t length = d->ReadUnsigned();
-      bool is_canonical = d->Read<bool>();
-      Deserializer::InitializeHeader(str, kOneByteStringCid,
-                                     OneByteString::InstanceSize(length),
-                                     is_canonical);
-      str->ptr()->length_ = Smi::New(length);
-      String::SetCachedHash(str, d->Read<int32_t>());
-      for (intptr_t j = 0; j < length; j++) {
-        str->ptr()->data()[j] = d->Read<uint8_t>();
-      }
-    }
-  }
-};
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
-class TwoByteStringSerializationCluster : public SerializationCluster {
- public:
-  TwoByteStringSerializationCluster() : SerializationCluster("TwoByteString") {}
-  ~TwoByteStringSerializationCluster() {}
-
-  void Trace(Serializer* s, RawObject* object) {
-    RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(object);
-    objects_.Add(str);
-  }
-
-  void WriteAlloc(Serializer* s) {
-    s->WriteCid(kTwoByteStringCid);
-    intptr_t count = objects_.length();
-    s->WriteUnsigned(count);
-    for (intptr_t i = 0; i < count; i++) {
-      RawTwoByteString* str = objects_[i];
-      s->AssignRef(str);
-      AutoTraceObject(str);
-      intptr_t length = Smi::Value(str->ptr()->length_);
-      s->WriteUnsigned(length);
-    }
-  }
-
-  void WriteFill(Serializer* s) {
-    intptr_t count = objects_.length();
-    for (intptr_t i = 0; i < count; i++) {
-      RawTwoByteString* str = objects_[i];
-      AutoTraceObject(str);
-      intptr_t length = Smi::Value(str->ptr()->length_);
-      s->WriteUnsigned(length);
-      s->Write<bool>(str->IsCanonical());
-      intptr_t hash = String::GetCachedHash(str);
-      s->Write<int32_t>(hash);
-      s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
-    }
-  }
-
- private:
-  GrowableArray<RawTwoByteString*> objects_;
-};
-#endif  // !DART_PRECOMPILED_RUNTIME
-
-class TwoByteStringDeserializationCluster : public DeserializationCluster {
- public:
-  TwoByteStringDeserializationCluster() {}
-  ~TwoByteStringDeserializationCluster() {}
-
-  void ReadAlloc(Deserializer* d) {
-    start_index_ = d->next_index();
-    PageSpace* old_space = d->heap()->old_space();
-    intptr_t count = d->ReadUnsigned();
-    for (intptr_t i = 0; i < count; i++) {
-      intptr_t length = d->ReadUnsigned();
-      d->AssignRef(AllocateUninitialized(old_space,
-                                         TwoByteString::InstanceSize(length)));
-    }
-    stop_index_ = d->next_index();
-  }
-
-  void ReadFill(Deserializer* d) {
-    for (intptr_t id = start_index_; id < stop_index_; id++) {
-      RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(d->Ref(id));
-      intptr_t length = d->ReadUnsigned();
-      bool is_canonical = d->Read<bool>();
-      Deserializer::InitializeHeader(str, kTwoByteStringCid,
-                                     TwoByteString::InstanceSize(length),
-                                     is_canonical);
-      str->ptr()->length_ = Smi::New(length);
-      String::SetCachedHash(str, d->Read<int32_t>());
-      uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
-      d->ReadBytes(cdata, length * 2);
-    }
-  }
-};
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
 class FakeSerializationCluster : public SerializationCluster {
  public:
   FakeSerializationCluster(const char* name, intptr_t size)
@@ -4369,16 +4205,10 @@
 
   if (Snapshot::IncludesCode(kind_)) {
     switch (cid) {
-      case kPcDescriptorsCid:
-        return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
       case kCodeSourceMapCid:
         return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
       case kStackMapCid:
         return new (Z) RODataSerializationCluster("(RO)StackMap", cid);
-      case kOneByteStringCid:
-        return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
-      case kTwoByteStringCid:
-        return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
     }
   }
 
@@ -4417,6 +4247,8 @@
 #endif  // !DART_PRECOMPILED_RUNTIME
     case kObjectPoolCid:
       return new (Z) ObjectPoolSerializationCluster();
+    case kPcDescriptorsCid:
+      return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
     case kExceptionHandlersCid:
       return new (Z) ExceptionHandlersSerializationCluster();
     case kContextCid:
@@ -4466,9 +4298,9 @@
     case kImmutableArrayCid:
       return new (Z) ArraySerializationCluster(kImmutableArrayCid);
     case kOneByteStringCid:
-      return new (Z) OneByteStringSerializationCluster();
+      return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
     case kTwoByteStringCid:
-      return new (Z) TwoByteStringSerializationCluster();
+      return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
     default:
       break;
   }
@@ -4962,17 +4794,15 @@
       zone_(thread->zone()),
       kind_(kind),
       stream_(buffer, size),
-      image_reader_(NULL),
-      refs_(NULL),
+      image_reader_(nullptr),
+      refs_(nullptr),
       next_ref_index_(1),
-      clusters_(NULL) {
-  if (Snapshot::IncludesCode(kind)) {
-    ASSERT(instructions_buffer != NULL);
-    ASSERT(data_buffer != NULL);
-    image_reader_ =
-        new (zone_) ImageReader(data_buffer, instructions_buffer,
-                                shared_data_buffer, shared_instructions_buffer);
-  }
+      clusters_(nullptr) {
+  ASSERT((instructions_buffer != nullptr) || !Snapshot::IncludesCode(kind));
+  ASSERT(data_buffer != nullptr);
+  image_reader_ =
+      new (zone_) ImageReader(data_buffer, instructions_buffer,
+                              shared_data_buffer, shared_instructions_buffer);
   stream_.SetPosition(offset);
 }
 
@@ -5085,25 +4915,14 @@
       return new (Z) ArrayDeserializationCluster(kArrayCid);
     case kImmutableArrayCid:
       return new (Z) ArrayDeserializationCluster(kImmutableArrayCid);
-    case kOneByteStringCid: {
-      if (Snapshot::IncludesCode(kind_)) {
-        return new (Z) RODataDeserializationCluster();
-      } else {
-        return new (Z) OneByteStringDeserializationCluster();
-      }
-    }
-    case kTwoByteStringCid: {
-      if (Snapshot::IncludesCode(kind_)) {
-        return new (Z) RODataDeserializationCluster();
-      } else {
-        return new (Z) TwoByteStringDeserializationCluster();
-      }
-    }
+    case kOneByteStringCid:
+    case kTwoByteStringCid:
+      return new (Z) RODataDeserializationCluster();
     default:
       break;
   }
   FATAL1("No cluster defined for cid %" Pd, cid);
-  return NULL;
+  return nullptr;
 }
 
 RawApiError* Deserializer::VerifyImageAlignment() {
@@ -5144,7 +4963,7 @@
   const char* version =
       reinterpret_cast<const char*>(stream_.AddressOfCurrentPosition());
   ASSERT(version != NULL);
-  if (strncmp(version, expected_version, version_len)) {
+  if (strncmp(version, expected_version, version_len) != 0) {
     const intptr_t kMessageBufferSize = 256;
     char message_buffer[kMessageBufferSize];
     char* actual_version = Utils::StrNDup(version, version_len);
@@ -5175,7 +4994,7 @@
   }
 
   if (features_length != expected_len ||
-      strncmp(features, expected_features, expected_len)) {
+      (strncmp(features, expected_features, expected_len) != 0)) {
     const intptr_t kMessageBufferSize = 1024;
     char message_buffer[kMessageBufferSize];
     char* actual_features = Utils::StrNDup(
@@ -5490,7 +5309,8 @@
 intptr_t FullSnapshotWriter::WriteVMSnapshot() {
   TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
 
-  ASSERT(vm_snapshot_data_buffer_ != NULL);
+  ASSERT(vm_snapshot_data_buffer_ != nullptr);
+  ASSERT(vm_image_writer_ != nullptr);
   Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
                         kInitialSize, vm_image_writer_, /*vm=*/true,
                         profile_writer_);
@@ -5507,14 +5327,12 @@
   serializer.FillHeader(serializer.kind());
   clustered_vm_size_ = serializer.bytes_written();
 
-  if (Snapshot::IncludesCode(kind_)) {
-    vm_image_writer_->SetProfileWriter(profile_writer_);
-    vm_image_writer_->Write(serializer.stream(), true);
-    mapped_data_size_ += vm_image_writer_->data_size();
-    mapped_text_size_ += vm_image_writer_->text_size();
-    vm_image_writer_->ResetOffsets();
-    vm_image_writer_->ClearProfileWriter();
-  }
+  vm_image_writer_->SetProfileWriter(profile_writer_);
+  vm_image_writer_->Write(serializer.stream(), true);
+  mapped_data_size_ += vm_image_writer_->data_size();
+  mapped_text_size_ += vm_image_writer_->text_size();
+  vm_image_writer_->ResetOffsets();
+  vm_image_writer_->ClearProfileWriter();
 
   // The clustered part + the direct mapped data part.
   vm_isolate_snapshot_size_ = serializer.bytes_written();
@@ -5524,11 +5342,13 @@
 void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) {
   TIMELINE_DURATION(thread(), Isolate, "WriteIsolateSnapshot");
 
+  ASSERT(isolate_snapshot_data_buffer_ != nullptr);
+  ASSERT(isolate_image_writer_ != nullptr);
   Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
                         kInitialSize, isolate_image_writer_, /*vm=*/false,
                         profile_writer_);
   ObjectStore* object_store = isolate()->object_store();
-  ASSERT(object_store != NULL);
+  ASSERT(object_store != nullptr);
 
   serializer.ReserveHeader();
   serializer.WriteVersionAndFeatures(false);
@@ -5538,18 +5358,16 @@
   serializer.FillHeader(serializer.kind());
   clustered_isolate_size_ = serializer.bytes_written();
 
-  if (Snapshot::IncludesCode(kind_)) {
-    isolate_image_writer_->SetProfileWriter(profile_writer_);
-    isolate_image_writer_->Write(serializer.stream(), false);
+  isolate_image_writer_->SetProfileWriter(profile_writer_);
+  isolate_image_writer_->Write(serializer.stream(), false);
 #if defined(DART_PRECOMPILER)
-    isolate_image_writer_->DumpStatistics();
+  isolate_image_writer_->DumpStatistics();
 #endif
 
-    mapped_data_size_ += isolate_image_writer_->data_size();
-    mapped_text_size_ += isolate_image_writer_->text_size();
-    isolate_image_writer_->ResetOffsets();
-    isolate_image_writer_->ClearProfileWriter();
-  }
+  mapped_data_size_ += isolate_image_writer_->data_size();
+  mapped_text_size_ += isolate_image_writer_->text_size();
+  isolate_image_writer_->ResetOffsets();
+  isolate_image_writer_->ClearProfileWriter();
 
   // The clustered part + the direct mapped data part.
   isolate_snapshot_size_ = serializer.bytes_written();
@@ -5670,11 +5488,11 @@
     return api_error;
   }
 
+  ASSERT(data_image_ != nullptr);
+  thread_->isolate()->SetupImagePage(data_image_,
+                                     /* is_executable */ false);
   if (Snapshot::IncludesCode(kind_)) {
-    ASSERT(data_image_ != NULL);
-    thread_->isolate()->SetupImagePage(data_image_,
-                                       /* is_executable */ false);
-    ASSERT(instructions_image_ != NULL);
+    ASSERT(instructions_image_ != nullptr);
     thread_->isolate()->SetupImagePage(instructions_image_,
                                        /* is_executable */ true);
   }
@@ -5701,18 +5519,18 @@
     return api_error;
   }
 
+  ASSERT(data_image_ != nullptr);
+  thread_->isolate()->SetupImagePage(data_image_,
+                                     /* is_executable */ false);
   if (Snapshot::IncludesCode(kind_)) {
-    ASSERT(data_image_ != NULL);
-    thread_->isolate()->SetupImagePage(data_image_,
-                                       /* is_executable */ false);
-    ASSERT(instructions_image_ != NULL);
+    ASSERT(instructions_image_ != nullptr);
     thread_->isolate()->SetupImagePage(instructions_image_,
                                        /* is_executable */ true);
-    if (shared_data_image_ != NULL) {
+    if (shared_data_image_ != nullptr) {
       thread_->isolate()->SetupImagePage(shared_data_image_,
                                          /* is_executable */ false);
     }
-    if (shared_instructions_image_ != NULL) {
+    if (shared_instructions_image_ != nullptr) {
       thread_->isolate()->SetupImagePage(shared_instructions_image_,
                                          /* is_executable */ true);
     }
@@ -5750,6 +5568,17 @@
       }
     }
   }
+
+  // Initialize symbols in the BSS, if present.
+  ASSERT(Snapshot::IncludesCode(kind_));
+  Image image(instructions_image_);
+  if (image.bss_offset() != 0) {
+    // The const cast is safe because we're translating from the start of the
+    // instructions (read-only) to the start of the BSS (read-write).
+    uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
+        instructions_image_ + image.bss_offset()));
+    BSS::Initialize(thread_, bss_start);
+  }
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 
   return ApiError::null();
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 2233715..f62744a 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -259,11 +259,6 @@
           return WriteRefId(Object::null());
         }
 #endif  // !DART_PRECOMPILED_RUNTIME
-        if (object->IsSendPort()) {
-          // TODO(rmacnak): Do a better job of resetting fields in
-          // precompilation and assert this is unreachable.
-          return WriteRefId(Object::null());
-        }
         FATAL("Missing ref");
       }
     }
@@ -533,7 +528,10 @@
     for (RawObject** p = from; p <= to_snapshot; p++) {
       *p = ReadRef();
     }
-    // TODO(sjindel/rmacnak): Is this really necessary?
+    // This is necessary because, unlike Object::Allocate, the clustered
+    // deserializer allocates object without null-initializing them. Instead,
+    // each deserialization cluster is responsible for initializing every field,
+    // ensuring that every field is written to exactly once.
     for (RawObject** p = to_snapshot + 1; p <= to; p++) {
       *p = Object::null();
     }
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 7d1b764..149de08 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -15,10 +15,13 @@
                                    TokenPosition token_pos,
                                    intptr_t try_index) {
   ASSERT((kind == RawPcDescriptors::kRuntimeCall) ||
+         (kind == RawPcDescriptors::kBSSRelocation) ||
          (kind == RawPcDescriptors::kOther) || (deopt_id != DeoptId::kNone));
 
-  // When precompiling, we only use pc descriptors for exceptions.
-  if (!FLAG_precompiled_mode || try_index != -1) {
+  // When precompiling, we only use pc descriptors for exceptions and
+  // relocations.
+  if (!FLAG_precompiled_mode || try_index != -1 ||
+      kind == RawPcDescriptors::kBSSRelocation) {
     int32_t merged_kind_try =
         RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
 
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index af8d622..e2f4eb8 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -500,7 +500,7 @@
       WriteString(str_);
 
       WriteInt(field_.guarded_cid());
-      WriteInt(field_.is_nullable());
+      WriteInt(static_cast<intptr_t>(field_.is_nullable()));
     }
   }
 }
@@ -673,7 +673,7 @@
   const char* version =
       reinterpret_cast<const char*>(stream_->AddressOfCurrentPosition());
   ASSERT(version != NULL);
-  if (strncmp(version, expected_version, version_len)) {
+  if (strncmp(version, expected_version, version_len) != 0) {
     const intptr_t kMessageBufferSize = 256;
     char message_buffer[kMessageBufferSize];
     char* actual_version = Utils::StrNDup(version, version_len);
@@ -695,7 +695,7 @@
   ASSERT(features != NULL);
   intptr_t buffer_len = Utils::StrNLen(features, stream_->PendingBytes());
   if ((buffer_len != expected_len) ||
-      strncmp(features, expected_features, expected_len)) {
+      (strncmp(features, expected_features, expected_len) != 0)) {
     const String& msg = String::Handle(String::NewFormatted(
         Heap::kOld,
         "Feedback not compatible with the current VM configuration: "
@@ -783,7 +783,7 @@
         field_.set_is_nullable(true);
       } else {
         field_.set_guarded_cid(guarded_cid);
-        field_.set_is_nullable(is_nullable || field_.is_nullable());
+        field_.set_is_nullable((is_nullable != 0) || field_.is_nullable());
       }
 
       // TODO(rmacnak): Merge other field type feedback.
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 5b1d22a..375e171 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -109,10 +109,9 @@
     return false;
   }
 
-  const ICData& ic_data =
-      ICData::ZoneHandle(Z, ICData::NewFrom(*call->ic_data(), 1));
-  ic_data.AddReceiverCheck(cls.id(), target_function);
-  call->set_ic_data(&ic_data);
+  call->SetTargets(
+      CallTargets::CreateMonomorphic(Z, cls.id(), target_function));
+  ASSERT(call->Targets().IsMonomorphic());
 
   // If we know that the only noSuchMethod is Object.noSuchMethod then
   // this call is guaranteed to either succeed or throw.
@@ -242,14 +241,9 @@
   if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
     return true;
   }
-
-  const ICData& unary_checks =
-      ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
-  if (!unary_checks.NumberOfChecksIs(0) && (op_kind == Token::kSET) &&
-      TryInlineInstanceSetter(call, unary_checks)) {
+  if ((op_kind == Token::kSET) && TryInlineInstanceSetter(call)) {
     return true;
   }
-
   return false;
 }
 
@@ -445,12 +439,12 @@
   right_definition = new (Z)
       IntConverterInstr(kUnboxedInt32, kUnboxedInt64,
                         new (Z) Value(right_definition), DeoptId::kNone);
-  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
 #else
   Definition* right_definition = new (Z) UnboxedConstantInstr(
       Smi::ZoneHandle(Z, Smi::New(modulus - 1)), kUnboxedInt64);
-  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
 #endif
+  if (modulus == 1) return right_definition;
+  InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
   right_value = new (Z) Value(right_definition);
   return new (Z)
       BinaryInt64OpInstr(Token::kBIT_AND, left_value, right_value,
@@ -787,22 +781,18 @@
     return;
   }
 
+  const CallTargets& targets = instr->Targets();
   const intptr_t receiver_idx = instr->FirstArgIndex();
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
-  const intptr_t number_of_checks = unary_checks.NumberOfChecks();
   if (I->can_use_strong_mode_types()) {
     // In AOT strong mode, we avoid deopting speculation.
     // TODO(ajcbik): replace this with actual analysis phase
     //               that determines if checks are removed later.
   } else if (speculative_policy_->IsAllowedForInlining(instr->deopt_id()) &&
-             number_of_checks > 0) {
-    if ((op_kind == Token::kINDEX) &&
-        TryReplaceWithIndexedOp(instr, &unary_checks)) {
+             !targets.is_empty()) {
+    if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
       return;
     }
-    if ((op_kind == Token::kASSIGN_INDEX) &&
-        TryReplaceWithIndexedOp(instr, &unary_checks)) {
+    if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
       return;
     }
     if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) {
@@ -833,25 +823,22 @@
     return;
   }
 
-  bool has_one_target = number_of_checks > 0 && unary_checks.HasOneTarget();
+  bool has_one_target = targets.HasSingleTarget();
   if (has_one_target) {
     // Check if the single target is a polymorphic target, if it is,
     // we don't have one target.
-    const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
+    const Function& target = targets.FirstTarget();
     const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
     has_one_target = !polymorphic_target;
   }
 
   if (has_one_target) {
-    RawFunction::Kind function_kind =
-        Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
+    const Function& target = targets.FirstTarget();
+    RawFunction::Kind function_kind = target.kind();
     if (flow_graph()->CheckForInstanceCall(instr, function_kind) ==
         FlowGraph::ToCheck::kNoCheck) {
-      CallTargets* targets = CallTargets::Create(Z, unary_checks);
-      ASSERT(targets->HasSingleTarget());
-      const Function& target = targets->FirstTarget();
       StaticCallInstr* call = StaticCallInstr::FromCall(
-          Z, instr, target, targets->AggregateCallCount());
+          Z, instr, target, targets.AggregateCallCount());
       instr->ReplaceWith(call, current_iterator());
       return;
     }
@@ -864,7 +851,7 @@
     case Token::kLTE:
     case Token::kGT:
     case Token::kGTE: {
-      if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
+      if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
           HasLikelySmiOperand(instr)) {
         ASSERT(receiver_idx == 0);
         Definition* left = instr->ArgumentAt(0);
@@ -885,7 +872,7 @@
     case Token::kADD:
     case Token::kSUB:
     case Token::kMUL: {
-      if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
+      if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
           HasLikelySmiOperand(instr)) {
         ASSERT(receiver_idx == 0);
         Definition* left = instr->ArgumentAt(0);
@@ -1033,7 +1020,8 @@
         return;
       } else if ((ic_data.raw() != ICData::null()) &&
                  !ic_data.NumberOfChecksIs(0)) {
-        CallTargets* targets = CallTargets::Create(Z, ic_data);
+        const CallTargets* targets = CallTargets::Create(Z, ic_data);
+        ASSERT(!targets->is_empty());
         PolymorphicInstanceCallInstr* call =
             new (Z) PolymorphicInstanceCallInstr(instr, *targets,
                                                  /* complete = */ true);
@@ -1051,13 +1039,12 @@
 
   // More than one target. Generate generic polymorphic call without
   // deoptimization.
-  if (instr->ic_data()->NumberOfUsedChecks() > 0) {
+  if (targets.length() > 0) {
     ASSERT(!FLAG_polymorphic_with_deopt);
     // OK to use checks with PolymorphicInstanceCallInstr since no
     // deoptimization is allowed.
-    CallTargets* targets = CallTargets::Create(Z, *instr->ic_data());
     PolymorphicInstanceCallInstr* call =
-        new (Z) PolymorphicInstanceCallInstr(instr, *targets,
+        new (Z) PolymorphicInstanceCallInstr(instr, targets,
                                              /* complete = */ false);
     instr->ReplaceWith(call, current_iterator());
     return;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index f6cc489..3e9c86ea 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -158,9 +158,11 @@
       pending_functions_(
           GrowableObjectArray::Handle(GrowableObjectArray::New())),
       sent_selectors_(),
-      enqueued_functions_(),
+      enqueued_functions_(
+          HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
       fields_to_retain_(),
-      functions_to_retain_(),
+      functions_to_retain_(
+          HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
       classes_to_retain_(),
       typeargs_to_retain_(),
       types_to_retain_(),
@@ -173,6 +175,10 @@
 }
 
 Precompiler::~Precompiler() {
+  // We have to call Release() in DEBUG mode.
+  enqueued_functions_.Release();
+  functions_to_retain_.Release();
+
   ASSERT(Precompiler::singleton_ == this);
   Precompiler::singleton_ = NULL;
 }
@@ -700,11 +706,11 @@
 
 void Precompiler::AddTypesOf(const Function& function) {
   if (function.IsNull()) return;
-  if (functions_to_retain_.HasKey(&function)) return;
+  if (functions_to_retain_.ContainsKey(function)) return;
   // We don't expect to see a reference to a redirecting factory. Only its
   // target should remain.
   ASSERT(!function.IsRedirectingFactory());
-  functions_to_retain_.Insert(&Function::ZoneHandle(Z, function.raw()));
+  functions_to_retain_.Insert(function);
 
   AbstractType& type = AbstractType::Handle(Z);
   type = function.result_type();
@@ -938,9 +944,9 @@
 }
 
 void Precompiler::AddFunction(const Function& function) {
-  if (enqueued_functions_.HasKey(&function)) return;
+  if (enqueued_functions_.ContainsKey(function)) return;
 
-  enqueued_functions_.Insert(&Function::ZoneHandle(Z, function.raw()));
+  enqueued_functions_.Insert(function);
   pending_functions_.Add(function);
   changed_ = true;
 }
@@ -1340,7 +1346,7 @@
       functions = cls.functions();
       for (intptr_t j = 0; j < functions.Length(); j++) {
         function ^= functions.At(j);
-        bool retain = enqueued_functions_.HasKey(&function);
+        bool retain = enqueued_functions_.ContainsKey(function);
         if (!retain && function.HasImplicitClosureFunction()) {
           // It can happen that all uses of an implicit closure inline their
           // target function, leaving the target function uncompiled. Keep
@@ -1360,7 +1366,7 @@
   closures = isolate()->object_store()->closure_functions();
   for (intptr_t j = 0; j < closures.Length(); j++) {
     function ^= closures.At(j);
-    bool retain = enqueued_functions_.HasKey(&function);
+    bool retain = enqueued_functions_.ContainsKey(function);
     if (retain) {
       AddTypesOf(function);
 
@@ -1400,7 +1406,7 @@
       retained_functions = GrowableObjectArray::New();
       for (intptr_t j = 0; j < functions.Length(); j++) {
         function ^= functions.At(j);
-        bool retain = functions_to_retain_.HasKey(&function);
+        bool retain = functions_to_retain_.ContainsKey(function);
         function.DropUncompiledImplicitClosureFunction();
         if (retain) {
           retained_functions.Add(function);
@@ -1426,7 +1432,7 @@
   retained_functions = GrowableObjectArray::New();
   for (intptr_t j = 0; j < closures.Length(); j++) {
     function ^= closures.At(j);
-    bool retain = functions_to_retain_.HasKey(&function);
+    bool retain = functions_to_retain_.ContainsKey(function);
     if (retain) {
       retained_functions.Add(function);
     } else {
@@ -1763,7 +1769,7 @@
           continue;
         }
       } else if (entry.IsFunction()) {
-        if (functions_to_retain_.HasKey(&Function::Cast(entry))) {
+        if (functions_to_retain_.ContainsKey(Function::Cast(entry))) {
           used++;
           continue;
         }
@@ -1999,10 +2005,11 @@
   // finally clauses, and not all functions are compiled through the
   // tree-shaker's queue
   ProgramVisitor::VisitFunctions(&visitor);
-  FunctionSet::Iterator it(enqueued_functions_.GetIterator());
-  for (const Function** current = it.Next(); current != NULL;
-       current = it.Next()) {
-    visitor.Visit(**current);
+  FunctionSet::Iterator it(&enqueued_functions_);
+  Function& handle = Function::Handle();
+  while (it.MoveNext()) {
+    handle ^= enqueued_functions_.GetKey(it.Current());
+    visitor.Visit(handle);
   }
 }
 
@@ -2085,10 +2092,11 @@
     // duplicated finally clauses, and not all functions are compiled through
     // the tree-shaker's queue
     ProgramVisitor::VisitFunctions(&visitor);
-    FunctionSet::Iterator it(enqueued_functions_.GetIterator());
-    for (const Function** current = it.Next(); current != NULL;
-         current = it.Next()) {
-      visitor.Visit(**current);
+    FunctionSet::Iterator it(&enqueued_functions_);
+    Function& current = Function::Handle();
+    while (it.MoveNext()) {
+      current ^= enqueued_functions_.GetKey(it.Current());
+      visitor.Visit(current);
     }
   }
 #endif
@@ -2219,8 +2227,6 @@
     function.set_unoptimized_code(code);
     function.AttachCode(code);
   }
-  ASSERT(!parsed_function()->HasDeferredPrefixes());
-  ASSERT(FLAG_load_deferred_eagerly);
 }
 
 // Return false if bailed out.
@@ -2285,7 +2291,12 @@
       pass_state.reorder_blocks =
           FlowGraph::ShouldReorderBlocks(function, optimized());
 
-      if (optimized()) {
+      if (function.ForceOptimize()) {
+        ASSERT(optimized());
+        TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
+        flow_graph = CompilerPass::RunForceOptimizedPipeline(CompilerPass::kAOT,
+                                                             &pass_state);
+      } else if (optimized()) {
         TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
 
         pass_state.inline_id_to_function.Add(&function);
@@ -2302,7 +2313,7 @@
                                             &speculative_policy);
         pass_state.call_specializer = &call_specializer;
 
-        CompilerPass::RunPipeline(CompilerPass::kAOT, &pass_state);
+        flow_graph = CompilerPass::RunPipeline(CompilerPass::kAOT, &pass_state);
       }
 
       ASSERT(pass_state.inline_id_to_function.length() ==
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 7dfa666..a6ceb59 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -72,37 +72,17 @@
 
 typedef DirectChainedHashMap<UnlinkedCallKeyValueTrait> UnlinkedCallSet;
 
-static inline intptr_t SimplePointerHash(void* ptr) {
-  return reinterpret_cast<intptr_t>(ptr) * 2654435761UL;
-}
-
-class FunctionKeyValueTrait {
- public:
-  // Typedefs needed for the DirectChainedHashMap template.
-  typedef const Function* Key;
-  typedef const Function* Value;
-  typedef const Function* Pair;
-
-  static Key KeyOf(Pair kv) { return kv; }
-
-  static Value ValueOf(Pair kv) { return kv; }
-
-  static inline intptr_t Hashcode(Key key) {
-    // We are using pointer hash for objects originating from Kernel because
-    // Fasta currently does not assign any position information to them.
-    if (key->kernel_offset() > 0) {
-      return key->kernel_offset();
-    } else {
-      return key->token_pos().value();
-    }
+// Traits for the HashTable template.
+struct FunctionKeyTraits {
+  static uint32_t Hash(const Object& key) { return Function::Cast(key).Hash(); }
+  static const char* Name() { return "FunctionKeyTraits"; }
+  static bool IsMatch(const Object& x, const Object& y) {
+    return x.raw() == y.raw();
   }
-
-  static inline bool IsKeyEqual(Pair pair, Key key) {
-    return pair->raw() == key->raw();
-  }
+  static bool ReportStats() { return false; }
 };
 
-typedef DirectChainedHashMap<FunctionKeyValueTrait> FunctionSet;
+typedef UnorderedHashSet<FunctionKeyTraits> FunctionSet;
 
 class FieldKeyValueTrait {
  public:
diff --git a/runtime/vm/compiler/assembler/assembler.cc b/runtime/vm/compiler/assembler/assembler.cc
index f6c6175..6b5427d 100644
--- a/runtime/vm/compiler/assembler/assembler.cc
+++ b/runtime/vm/compiler/assembler/assembler.cc
@@ -30,6 +30,31 @@
 
 namespace compiler {
 
+AssemblerBase::~AssemblerBase() {}
+
+intptr_t AssemblerBase::InsertAlignedRelocation(BSS::Relocation reloc) {
+  // We cannot put a relocation at the very start (it's not a valid
+  // instruction)!
+  ASSERT(CodeSize() != 0);
+
+  // Align to a target word boundary.
+  const intptr_t offset =
+      Utils::RoundUp(CodeSize(), compiler::target::kWordSize);
+
+  while (CodeSize() < offset) {
+    Breakpoint();
+  }
+  ASSERT(CodeSize() == offset);
+
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  buffer_.Emit<compiler::target::word>(BSS::RelocationIndex(reloc) *
+                                       compiler::target::kWordSize);
+
+  ASSERT(CodeSize() == (offset + compiler::target::kWordSize));
+
+  return offset;
+}
+
 static uword NewContents(intptr_t capacity) {
   Zone* zone = Thread::Current()->zone();
   uword result = zone->AllocUnsafe(capacity);
diff --git a/runtime/vm/compiler/assembler/assembler.h b/runtime/vm/compiler/assembler/assembler.h
index cf4d6e6..645728a 100644
--- a/runtime/vm/compiler/assembler/assembler.h
+++ b/runtime/vm/compiler/assembler/assembler.h
@@ -305,7 +305,7 @@
         prologue_offset_(-1),
         has_single_entry_point_(true),
         object_pool_builder_(object_pool_builder) {}
-  virtual ~AssemblerBase() {}
+  virtual ~AssemblerBase();
 
   intptr_t CodeSize() const { return buffer_.Size(); }
 
@@ -320,6 +320,10 @@
   void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
   static bool EmittingComments();
 
+  virtual void Breakpoint() = 0;
+
+  intptr_t InsertAlignedRelocation(BSS::Relocation reloc);
+
   void Unimplemented(const char* message);
   void Untested(const char* message);
   void Unreachable(const char* message);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 7a55232..667f8a5 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -392,7 +392,7 @@
 #endif  // TESTING || DEBUG
 
   // Debugging and bringup support.
-  void Breakpoint() { bkpt(0); }
+  void Breakpoint() override { bkpt(0); }
   void Stop(const char* message) override;
 
   static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index e8c565e..d945c0e 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -485,7 +485,7 @@
   void set_use_far_branches(bool b) { use_far_branches_ = b; }
 
   // Debugging and bringup support.
-  void Breakpoint() { brk(0); }
+  void Breakpoint() override { brk(0); }
   void Stop(const char* message) override;
 
   static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_dbc.h b/runtime/vm/compiler/assembler/assembler_dbc.h
index df2a83c..0737026 100644
--- a/runtime/vm/compiler/assembler/assembler_dbc.h
+++ b/runtime/vm/compiler/assembler/assembler_dbc.h
@@ -43,6 +43,7 @@
   void MonomorphicCheckedEntryAOT() {}
 
   // Debugging and bringup support.
+  void Breakpoint() override { Stop("Breakpoint!"); }
   void Stop(const char* message) override;
 
   static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index 586b7dd..8321841 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -835,7 +835,7 @@
                         Register temp);
 
   // Debugging and bringup support.
-  void Breakpoint() { int3(); }
+  void Breakpoint() override { int3(); }
   void Stop(const char* message) override;
 
   static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index e5f9e7d..8bc626a 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1998,7 +1998,7 @@
     nop(MAX_NOP_SIZE);
     bytes_needed -= MAX_NOP_SIZE;
   }
-  if (bytes_needed) {
+  if (bytes_needed != 0) {
     nop(bytes_needed);
   }
   ASSERT(((offset + buffer_.GetPosition()) & (alignment - 1)) == 0);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index b519aae..9e69dc8 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -590,6 +590,7 @@
   REGULAR_UNARY(not, 0xF7, 2)
   REGULAR_UNARY(neg, 0xF7, 3)
   REGULAR_UNARY(mul, 0xF7, 4)
+  REGULAR_UNARY(imul, 0xF7, 5)
   REGULAR_UNARY(div, 0xF7, 6)
   REGULAR_UNARY(idiv, 0xF7, 7)
   REGULAR_UNARY(inc, 0xFF, 0)
@@ -937,7 +938,7 @@
   void GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target = 0);
 
   // Debugging and bringup support.
-  void Breakpoint() { int3(); }
+  void Breakpoint() override { int3(); }
   void Stop(const char* message) override;
 
   static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_x64_test.cc b/runtime/vm/compiler/assembler/assembler_x64_test.cc
index 92aa14d..2e4609f 100644
--- a/runtime/vm/compiler/assembler/assembler_x64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64_test.cc
@@ -855,6 +855,25 @@
       "ret\n");
 }
 
+ASSEMBLER_TEST_GENERATE(SignedMultiply64Implicit, assembler) {
+  __ movq(RAX, Immediate(7));
+  __ movq(RDX, Immediate(-3));
+  __ imulq(RDX);  // // RDX:RAX = -21
+  __ addq(RAX, RDX);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(SignedMultiply64Implicit, test) {
+  typedef int (*SignedMultiply64Implicit)();
+  EXPECT_EQ(-22, reinterpret_cast<SignedMultiply64Implicit>(test->entry())());
+  EXPECT_DISASSEMBLY(
+      "movl rax,7\n"
+      "movq rdx,-3\n"
+      "imulq (rax,rdx),rdx\n"
+      "addq rax,rdx\n"
+      "ret\n");
+}
+
 ASSEMBLER_TEST_GENERATE(SignedMultiply64, assembler) {
   __ pushq(R15);  // Callee saved.
   __ movq(RAX, Immediate(2));
diff --git a/runtime/vm/compiler/assembler/disassembler_kbc.cc b/runtime/vm/compiler/assembler/disassembler_kbc.cc
index d2f0229..1cf9e00 100644
--- a/runtime/vm/compiler/assembler/disassembler_kbc.cc
+++ b/runtime/vm/compiler/assembler/disassembler_kbc.cc
@@ -315,7 +315,7 @@
                      hex_size - (i * kCharactersPerByte), " %02x", instr[i]);
     }
   }
-  if (out_instr_size) {
+  if (out_instr_size != nullptr) {
     *out_instr_size = instr_size;
   }
 
diff --git a/runtime/vm/compiler/assembler/disassembler_x86.cc b/runtime/vm/compiler/assembler/disassembler_x86.cc
index 7e4c016..6fd177e 100644
--- a/runtime/vm/compiler/assembler/disassembler_x86.cc
+++ b/runtime/vm/compiler/assembler/disassembler_x86.cc
@@ -1767,7 +1767,7 @@
         // mov reg8,imm8 or mov reg32,imm32
         uint8_t opcode = *data;
         data++;
-        uint8_t is_not_8bit = (opcode >= 0xB8);
+        const bool is_not_8bit = opcode >= 0xB8;
         int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
         if (is_not_8bit) {
           Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
@@ -1970,7 +1970,7 @@
     remaining_size -= 2;
   }
   hex_buffer[hex_index] = '\0';
-  if (out_instr_len) {
+  if (out_instr_len != nullptr) {
     *out_instr_len = instruction_length;
   }
 
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 11312bc..c883852 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -54,7 +54,6 @@
       prologue_info_(prologue_info),
       loop_hierarchy_(nullptr),
       loop_invariant_loads_(nullptr),
-      deferred_prefixes_(parsed_function.deferred_prefixes()),
       captured_parameters_(new (zone()) BitVector(zone(), variable_count())),
       inlining_id_(-1),
       should_print_(FlowGraphPrinter::ShouldPrint(parsed_function.function())) {
@@ -105,20 +104,6 @@
   iterator->RemoveCurrentFromGraph();
 }
 
-void FlowGraph::AddToDeferredPrefixes(
-    ZoneGrowableArray<const LibraryPrefix*>* from) {
-  ZoneGrowableArray<const LibraryPrefix*>* to = deferred_prefixes();
-  for (intptr_t i = 0; i < from->length(); i++) {
-    const LibraryPrefix* prefix = (*from)[i];
-    for (intptr_t j = 0; j < to->length(); j++) {
-      if ((*to)[j]->raw() == prefix->raw()) {
-        return;
-      }
-    }
-    to->Add(prefix);
-  }
-}
-
 bool FlowGraph::ShouldReorderBlocks(const Function& function,
                                     bool is_optimized) {
   return is_optimized && FLAG_reorder_basic_blocks &&
@@ -273,13 +258,19 @@
     if (merged->Contains(block->postorder_number())) continue;
 
     Instruction* last = block->last_instruction();
-    BlockEntryInstr* successor = NULL;
-    while ((!last->IsIndirectGoto()) && (last->SuccessorCount() == 1) &&
-           (!last->SuccessorAt(0)->IsIndirectEntry()) &&
-           (last->SuccessorAt(0)->PredecessorCount() == 1) &&
-           (block->try_index() == last->SuccessorAt(0)->try_index())) {
-      successor = last->SuccessorAt(0);
-      ASSERT(last->IsGoto());
+    BlockEntryInstr* last_merged_block = nullptr;
+    while (auto goto_instr = last->AsGoto()) {
+      JoinEntryInstr* successor = goto_instr->successor();
+      if (successor->PredecessorCount() > 1) break;
+      if (block->try_index() != successor->try_index()) break;
+
+      // Replace all phis with their arguments prior to removing successor.
+      for (PhiIterator it(successor); !it.Done(); it.Advance()) {
+        PhiInstr* phi = it.Current();
+        Value* input = phi->InputAt(0);
+        phi->ReplaceUsesWith(input->definition());
+        input->RemoveFromUseList();
+      }
 
       // Remove environment uses and unlink goto and block entry.
       successor->UnuseAllInputs();
@@ -288,6 +279,7 @@
 
       last = successor->last_instruction();
       merged->Add(successor->postorder_number());
+      last_merged_block = successor;
       changed = true;
       if (FLAG_trace_optimization) {
         THR_Print("Merged blocks B%" Pd " and B%" Pd "\n", block->block_id(),
@@ -296,8 +288,8 @@
     }
     // The new block inherits the block id of the last successor to maintain
     // the order of phi inputs at its successors consistent with block ids.
-    if (successor != NULL) {
-      block->set_block_id(successor->block_id());
+    if (last_merged_block != nullptr) {
+      block->set_block_id(last_merged_block->block_id());
     }
   }
   // Recompute block order after changes were made.
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index c138045..bbba0f1 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -341,12 +341,6 @@
 
   bool IsCompiledForOsr() const { return graph_entry()->IsCompiledForOsr(); }
 
-  void AddToDeferredPrefixes(ZoneGrowableArray<const LibraryPrefix*>* from);
-
-  ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
-    return deferred_prefixes_;
-  }
-
   BitVector* captured_parameters() const { return captured_parameters_; }
 
   intptr_t inlining_id() const { return inlining_id_; }
@@ -532,7 +526,6 @@
   LoopHierarchy* loop_hierarchy_;
   ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
 
-  ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
   DirectChainedHashMap<ConstantPoolTrait> constant_instr_pool_;
   BitVector* captured_parameters_;
 
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index 7e810b2..bde8521 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -224,6 +224,14 @@
 
 void FlowGraphChecker::VisitInstruction(Instruction* instruction) {
   ASSERT(!instruction->IsBlockEntry());
+
+  // In JIT mode, any instruction which may throw must have a deopt-id, except
+  // tail-call because it replaces the stack frame.
+#if !defined(DART_PRECOMPILER)
+  ASSERT(!instruction->MayThrow() || instruction->IsTailCall() ||
+         instruction->deopt_id() != DeoptId::kNone);
+#endif  // !defined(DART_PRECOMPILER)
+
   // Check all regular inputs.
   for (intptr_t i = 0, n = instruction->InputCount(); i < n; ++i) {
     VisitUseDef(instruction, instruction->InputAt(i), i, /*is_env*/ false);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index a0db6a8..49597bb9 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -242,6 +242,13 @@
   return isolate()->use_osr() && CanOptimizeFunction() && !is_optimizing();
 }
 
+void FlowGraphCompiler::InsertBSSRelocation(BSS::Relocation reloc) {
+  const intptr_t offset = assembler()->InsertAlignedRelocation(reloc);
+  AddDescriptor(RawPcDescriptors::kBSSRelocation, /*pc_offset=*/offset,
+                /*deopt_id=*/DeoptId::kNone, TokenPosition::kNoSource,
+                /*try_index=*/-1);
+}
+
 bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
 #if !defined(PRODUCT)
   if ((FLAG_stacktrace_every > 0) || (FLAG_deoptimize_every > 0) ||
@@ -1401,7 +1408,9 @@
                                : ic_data.arguments_descriptor());
   ASSERT(ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() ==
          args_info.type_args_len);
-  if (is_optimizing() && !ForcedOptimization()) {
+  // Force-optimized functions lack the deopt info which allows patching of
+  // optimized static calls.
+  if (is_optimizing() && (!ForcedOptimization() || FLAG_precompiled_mode)) {
     EmitOptimizedStaticCall(function, arguments_descriptor,
                             args_info.count_with_type_args, deopt_id, token_pos,
                             locs, entry_kind);
@@ -1413,6 +1422,7 @@
           GetOrAddStaticCallICData(deopt_id, function, arguments_descriptor,
                                    kNumArgsChecked, rebind_rule)
               ->raw();
+      call_ic_data = call_ic_data.Original();
     }
     AddCurrentDescriptor(RawPcDescriptors::kRewind, deopt_id, token_pos);
     EmitUnoptimizedStaticCall(args_info.count_with_type_args, deopt_id,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index fe10a80..f07d8d7 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -428,6 +428,8 @@
   bool CanOSRFunction() const;
   bool is_optimizing() const { return is_optimizing_; }
 
+  void InsertBSSRelocation(BSS::Relocation reloc);
+
   // The function was fully intrinsified, so the body is unreachable.
   //
   // We still need to compile the body in unoptimized mode because the
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 57915ca..af3e2f5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1108,8 +1108,8 @@
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
   const ArgumentsDescriptor args_desc(arguments_descriptor);
   const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
-                                                    arguments_descriptor));
+      zone(),
+      MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
 
   __ Comment("MegamorphicCall");
   // Load receiver into R0.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 192ec70..8c9f45d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -1074,8 +1074,8 @@
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
   const ArgumentsDescriptor args_desc(arguments_descriptor);
   const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
-                                                    arguments_descriptor));
+      zone(),
+      MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
 
   __ Comment("MegamorphicCall");
   // Load receiver into R0.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 3e1bd1f..5b1a9c3 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -969,8 +969,8 @@
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
   const ArgumentsDescriptor args_desc(arguments_descriptor);
   const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
-                                                    arguments_descriptor));
+      zone(),
+      MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
 
   __ Comment("MegamorphicCall");
   // Load receiver into EBX.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index ac328e6..78987ee 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -1094,8 +1094,8 @@
   ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
   const ArgumentsDescriptor args_desc(arguments_descriptor);
   const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
-      zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
-                                                    arguments_descriptor));
+      zone(),
+      MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
   __ Comment("MegamorphicCall");
   // Load receiver into RDX.
   __ movq(RDX, compiler::Address(RSP, (args_desc.Count() - 1) * kWordSize));
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 7c47f30..e3479a4 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -650,16 +650,22 @@
   return cids;
 }
 
-Cids* Cids::CreateAndExpand(Zone* zone,
-                            const ICData& ic_data,
-                            int argument_number) {
+Cids* Cids::CreateForArgument(Zone* zone,
+                              const BinaryFeedback& binary_feedback,
+                              int argument_number) {
   Cids* cids = new (zone) Cids(zone);
-  cids->CreateHelper(zone, ic_data, argument_number,
-                     /* include_targets = */ false);
-  cids->Sort(OrderById);
+  for (intptr_t i = 0; i < binary_feedback.feedback_.length(); i++) {
+    ASSERT((argument_number == 0) || (argument_number == 1));
+    const intptr_t cid = argument_number == 0
+                             ? binary_feedback.feedback_[i].first
+                             : binary_feedback.feedback_[i].second;
+    cids->Add(new (zone) CidRange(cid, cid));
+  }
 
-  // Merge adjacent class id ranges.
-  {
+  if (cids->length() != 0) {
+    cids->Sort(OrderById);
+
+    // Merge adjacent class id ranges.
     int dest = 0;
     for (int src = 1; src < cids->length(); src++) {
       if (cids->cid_ranges_[dest]->cid_end + 1 >=
@@ -673,53 +679,6 @@
     cids->SetLength(dest + 1);
   }
 
-  // Merging/extending cid ranges is also done in CallTargets::CreateAndExpand.
-  // If changing this code, consider also adjusting CallTargets code.
-
-  if (cids->length() > 1 && argument_number == 0 && ic_data.HasOneTarget()) {
-    // Try harder to merge ranges if method lookups in the gaps result in the
-    // same target method.
-    const Function& target = Function::Handle(zone, ic_data.GetTargetAt(0));
-    if (!MethodRecognizer::PolymorphicTarget(target)) {
-      const auto& args_desc_array =
-          Array::Handle(zone, ic_data.arguments_descriptor());
-      ArgumentsDescriptor args_desc(args_desc_array);
-      const auto& name = String::Handle(zone, ic_data.target_name());
-      auto& fn = Function::Handle(zone);
-
-      intptr_t dest = 0;
-      for (intptr_t src = 1; src < cids->length(); src++) {
-        // Inspect all cids in the gap and see if they all resolve to the same
-        // target.
-        bool can_merge = true;
-        for (intptr_t cid = cids->cid_ranges_[dest]->cid_end + 1,
-                      end = cids->cid_ranges_[src]->cid_start;
-             cid < end; ++cid) {
-          bool class_is_abstract = false;
-          if (FlowGraphCompiler::LookupMethodFor(cid, name, args_desc, &fn,
-                                                 &class_is_abstract)) {
-            if (fn.raw() == target.raw()) {
-              continue;
-            }
-            if (class_is_abstract) {
-              continue;
-            }
-          }
-          can_merge = false;
-          break;
-        }
-
-        if (can_merge) {
-          cids->cid_ranges_[dest]->cid_end = cids->cid_ranges_[src]->cid_end;
-        } else {
-          dest++;
-          if (src != dest) cids->cid_ranges_[dest] = cids->cid_ranges_[src];
-        }
-      }
-      cids->SetLength(dest + 1);
-    }
-  }
-
   return cids;
 }
 
@@ -740,64 +699,55 @@
   return count;
 }
 
-void Cids::CreateHelper(Zone* zone,
-                        const ICData& ic_data,
-                        int argument_number,
-                        bool include_targets) {
-  ASSERT(argument_number < ic_data.NumArgsTested());
-
-  if (ic_data.NumberOfChecks() == 0) return;
-
+void CallTargets::CreateHelper(Zone* zone, const ICData& ic_data) {
   Function& dummy = Function::Handle(zone);
 
-  bool check_one_arg = ic_data.NumArgsTested() == 1;
+  const intptr_t num_args_tested = ic_data.NumArgsTested();
 
-  int checks = ic_data.NumberOfChecks();
-  for (int i = 0; i < checks; i++) {
-    if (ic_data.GetCountAt(i) == 0) continue;
-    intptr_t id = 0;
-    if (check_one_arg) {
+  for (int i = 0, n = ic_data.NumberOfChecks(); i < n; i++) {
+    if (ic_data.GetCountAt(i) == 0) {
+      continue;
+    }
+
+    intptr_t id = kDynamicCid;
+    if (num_args_tested == 0) {
+    } else if (num_args_tested == 1) {
       ic_data.GetOneClassCheckAt(i, &id, &dummy);
     } else {
+      ASSERT(num_args_tested == 2);
       GrowableArray<intptr_t> arg_ids;
       ic_data.GetCheckAt(i, &arg_ids, &dummy);
-      id = arg_ids[argument_number];
+      id = arg_ids[0];
     }
-    if (include_targets) {
-      Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i));
-      intptr_t count = ic_data.GetCountAt(i);
-      cid_ranges_.Add(new (zone) TargetInfo(id, id, &function, count,
-                                            ic_data.GetExactnessAt(i)));
-    } else {
-      cid_ranges_.Add(new (zone) CidRange(id, id));
-    }
+    Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i));
+    intptr_t count = ic_data.GetCountAt(i);
+    cid_ranges_.Add(new (zone) TargetInfo(id, id, &function, count,
+                                          ic_data.GetExactnessAt(i)));
   }
 
   if (ic_data.is_megamorphic()) {
+    ASSERT(num_args_tested == 1);  // Only 1-arg ICData will turn megamorphic.
     const String& name = String::Handle(zone, ic_data.target_name());
     const Array& descriptor =
         Array::Handle(zone, ic_data.arguments_descriptor());
+    Thread* thread = Thread::Current();
     const MegamorphicCache& cache = MegamorphicCache::Handle(
-        zone, MegamorphicCacheTable::LookupClone(Thread::Current(), name,
-                                                 descriptor));
+        zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
+    SafepointMutexLocker ml(thread->isolate()->megamorphic_mutex());
     MegamorphicCacheEntries entries(Array::Handle(zone, cache.buckets()));
-    for (intptr_t i = 0; i < entries.Length(); i++) {
+    for (intptr_t i = 0, n = entries.Length(); i < n; i++) {
       const intptr_t id =
           Smi::Value(entries[i].Get<MegamorphicCache::kClassIdIndex>());
       if (id == kIllegalCid) {
         continue;
       }
-      if (include_targets) {
-        Function& function = Function::ZoneHandle(zone);
-        function ^= entries[i].Get<MegamorphicCache::kTargetFunctionIndex>();
-        const intptr_t filled_entry_count = cache.filled_entry_count();
-        ASSERT(filled_entry_count > 0);
-        cid_ranges_.Add(new (zone) TargetInfo(
-            id, id, &function, Usage(function) / filled_entry_count,
-            StaticTypeExactnessState::NotTracking()));
-      } else {
-        cid_ranges_.Add(new (zone) CidRange(id, id));
-      }
+      Function& function = Function::ZoneHandle(zone);
+      function ^= entries[i].Get<MegamorphicCache::kTargetFunctionIndex>();
+      const intptr_t filled_entry_count = cache.filled_entry_count();
+      ASSERT(filled_entry_count > 0);
+      cid_ranges_.Add(new (zone) TargetInfo(
+          id, id, &function, Usage(function) / filled_entry_count,
+          StaticTypeExactnessState::NotTracking()));
     }
   }
 }
@@ -812,6 +762,11 @@
   return cid_ranges_[0]->cid_start;
 }
 
+StaticTypeExactnessState CallTargets::MonomorphicExactness() const {
+  ASSERT(IsMonomorphic());
+  return TargetAt(0)->exactness;
+}
+
 CheckClassInstr::CheckClassInstr(Value* value,
                                  intptr_t deopt_id,
                                  const Cids& cids,
@@ -1113,9 +1068,14 @@
 
 GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
                                  intptr_t osr_id)
-    : BlockEntryWithInitialDefs(0,
-                                kInvalidTryIndex,
-                                CompilerState::Current().GetNextDeoptId()),
+    : GraphEntryInstr(parsed_function,
+                      osr_id,
+                      CompilerState::Current().GetNextDeoptId()) {}
+
+GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
+                                 intptr_t osr_id,
+                                 intptr_t deopt_id)
+    : BlockEntryWithInitialDefs(0, kInvalidTryIndex, deopt_id),
       parsed_function_(parsed_function),
       catch_entries_(),
       indirect_entries_(),
@@ -1651,6 +1611,7 @@
 
       auto goto_join = new GotoInstr(AsJoinEntry(),
                                      CompilerState::Current().GetNextDeoptId());
+      ASSERT(parent != nullptr);
       goto_join->CopyDeoptIdFrom(*parent);
       osr_entry->LinkTo(goto_join);
 
@@ -2021,6 +1982,26 @@
                               (64 - RepresentationBits(r)));
 }
 
+static int64_t TruncateTo(int64_t v, Representation r) {
+  switch (r) {
+    case kTagged: {
+      // Smi occupies word minus kSmiTagShift bits.
+      const intptr_t kTruncateBits =
+          (kBitsPerInt64 - kBitsPerWord) + kSmiTagShift;
+      return Utils::ShiftLeftWithTruncation(v, kTruncateBits) >> kTruncateBits;
+    }
+    case kUnboxedInt32:
+      return Utils::ShiftLeftWithTruncation(v, kBitsPerInt32) >> kBitsPerInt32;
+    case kUnboxedUint32:
+      return v & kMaxUint32;
+    case kUnboxedInt64:
+      return v;
+    default:
+      UNREACHABLE();
+      return 0;
+  }
+}
+
 static bool ToIntegerConstant(Value* value, int64_t* result) {
   if (!value->BindsToConstant()) {
     UnboxInstr* unbox = value->definition()->AsUnbox();
@@ -2032,7 +2013,7 @@
 
         case kUnboxedUint32:
           if (ToIntegerConstant(unbox->value(), result)) {
-            *result &= RepresentationMask(kUnboxedUint32);
+            *result = TruncateTo(*result, kUnboxedUint32);
             return true;
           }
           break;
@@ -2380,8 +2361,8 @@
 
   if (!result.IsNull()) {
     if (is_truncating()) {
-      int64_t truncated = result.AsTruncatedInt64Value();
-      truncated &= RepresentationMask(representation());
+      const int64_t truncated =
+          TruncateTo(result.AsTruncatedInt64Value(), representation());
       result = Integer::New(truncated, Heap::kOld);
       ASSERT(IsRepresentable(result, representation()));
     } else if (!IsRepresentable(result, representation())) {
@@ -2514,7 +2495,6 @@
     return this;
   }
 
-  const int64_t range_mask = RepresentationMask(representation());
   if (is_truncating()) {
     switch (op_kind()) {
       case Token::kMUL:
@@ -2523,7 +2503,7 @@
       case Token::kBIT_AND:
       case Token::kBIT_OR:
       case Token::kBIT_XOR:
-        rhs = (rhs & range_mask);
+        rhs = TruncateTo(rhs, representation());
         break;
       default:
         break;
@@ -2566,21 +2546,21 @@
     case Token::kBIT_AND:
       if (rhs == 0) {
         return right()->definition();
-      } else if (rhs == range_mask) {
+      } else if (rhs == RepresentationMask(representation())) {
         return left()->definition();
       }
       break;
     case Token::kBIT_OR:
       if (rhs == 0) {
         return left()->definition();
-      } else if (rhs == range_mask) {
+      } else if (rhs == RepresentationMask(representation())) {
         return right()->definition();
       }
       break;
     case Token::kBIT_XOR:
       if (rhs == 0) {
         return left()->definition();
-      } else if (rhs == range_mask) {
+      } else if (rhs == RepresentationMask(representation())) {
         UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make(
             representation(), Token::kBIT_NOT, left()->CopyWithType(),
             GetDeoptId(), range());
@@ -2611,6 +2591,12 @@
       }
       break;
 
+    case Token::kMOD:
+      if (std::abs(rhs) == 1) {
+        return CreateConstantResult(flow_graph, Object::smi_zero());
+      }
+      break;
+
     case Token::kSHR:
       if (rhs == 0) {
         return left()->definition();
@@ -3124,10 +3110,18 @@
     return replacement;
   }
 
-  IntConverterInstr* conv = value()->definition()->AsIntConverter();
-  if (conv != NULL) {
-    Definition* replacement = this;
+  // For all x, box(unbox(x)) = x.
+  if (auto unbox = value()->definition()->AsUnboxInt64()) {
+    if (unbox->speculative_mode() == kNotSpeculative) {
+      return unbox->value()->definition();
+    }
+  } else if (auto unbox = value()->definition()->AsUnboxedConstant()) {
+    return flow_graph->GetConstant(unbox->value());
+  }
 
+  // Find a more precise box instruction.
+  if (auto conv = value()->definition()->AsIntConverter()) {
+    Definition* replacement;
     switch (conv->from()) {
       case kUnboxedInt32:
         replacement = new BoxInt32Instr(conv->value()->CopyWithType());
@@ -3139,11 +3133,7 @@
         UNREACHABLE();
         break;
     }
-
-    if (replacement != this) {
-      flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
-    }
-
+    flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
     return replacement;
   }
 
@@ -3772,19 +3762,58 @@
   }
 }
 
-CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) {
+const BinaryFeedback* BinaryFeedback::Create(Zone* zone,
+                                             const ICData& ic_data) {
+  BinaryFeedback* result = new (zone) BinaryFeedback(zone);
+  if (ic_data.NumArgsTested() == 2) {
+    for (intptr_t i = 0, n = ic_data.NumberOfChecks(); i < n; i++) {
+      if (ic_data.GetCountAt(i) == 0) {
+        continue;
+      }
+      GrowableArray<intptr_t> arg_ids;
+      ic_data.GetClassIdsAt(i, &arg_ids);
+      result->feedback_.Add({arg_ids[0], arg_ids[1]});
+    }
+  }
+  return result;
+}
+
+const BinaryFeedback* BinaryFeedback::CreateMonomorphic(Zone* zone,
+                                                        intptr_t receiver_cid,
+                                                        intptr_t argument_cid) {
+  BinaryFeedback* result = new (zone) BinaryFeedback(zone);
+  result->feedback_.Add({receiver_cid, argument_cid});
+  return result;
+}
+
+const CallTargets* CallTargets::CreateMonomorphic(Zone* zone,
+                                                  intptr_t receiver_cid,
+                                                  const Function& target) {
   CallTargets* targets = new (zone) CallTargets(zone);
-  targets->CreateHelper(zone, ic_data, /* argument_number = */ 0,
-                        /* include_targets = */ true);
+  const intptr_t count = 1;
+  targets->cid_ranges_.Add(new (zone) TargetInfo(
+      receiver_cid, receiver_cid, &Function::ZoneHandle(zone, target.raw()),
+      count, StaticTypeExactnessState::NotTracking()));
+  return targets;
+}
+
+const CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) {
+  CallTargets* targets = new (zone) CallTargets(zone);
+  targets->CreateHelper(zone, ic_data);
   targets->Sort(OrderById);
   targets->MergeIntoRanges();
   return targets;
 }
 
-CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) {
+const CallTargets* CallTargets::CreateAndExpand(Zone* zone,
+                                                const ICData& ic_data) {
   CallTargets& targets = *new (zone) CallTargets(zone);
-  targets.CreateHelper(zone, ic_data, /* argument_number = */ 0,
-                       /* include_targets = */ true);
+  targets.CreateHelper(zone, ic_data);
+
+  if (targets.is_empty() || targets.IsMonomorphic()) {
+    return &targets;
+  }
+
   targets.Sort(OrderById);
 
   Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor());
@@ -3868,6 +3897,10 @@
 }
 
 void CallTargets::MergeIntoRanges() {
+  if (length() == 0) {
+    return;  // For correctness not performance: must not update length to 1.
+  }
+
   // Merge adjacent class id ranges.
   int dest = 0;
   // We merge entries that dispatch to the same target, but polymorphic targets
@@ -4239,6 +4272,30 @@
   }
 }
 
+const char* SpecialParameterInstr::KindToCString(SpecialParameterKind k) {
+  switch (k) {
+#define KIND_CASE(Name)                                                        \
+  case SpecialParameterKind::k##Name:                                          \
+    return #Name;
+    FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_CASE)
+#undef KIND_CASE
+  }
+  return nullptr;
+}
+
+bool SpecialParameterInstr::KindFromCString(const char* str,
+                                            SpecialParameterKind* out) {
+  ASSERT(str != nullptr && out != nullptr);
+#define KIND_CASE(Name)                                                        \
+  if (strcmp(str, #Name) == 0) {                                               \
+    *out = SpecialParameterKind::k##Name;                                      \
+    return true;                                                               \
+  }
+  FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_CASE)
+#undef KIND_CASE
+  return false;
+}
+
 LocationSummary* SpecialParameterInstr::MakeLocationSummary(Zone* zone,
                                                             bool opt) const {
   // Only appears in initial definitions, never in normal code.
@@ -4492,6 +4549,56 @@
                                                   args_desc, allow_add);
 }
 
+const CallTargets& InstanceCallInstr::Targets() {
+  if (targets_ == nullptr) {
+    Zone* zone = Thread::Current()->zone();
+    if (HasICData()) {
+      targets_ = CallTargets::CreateAndExpand(zone, *ic_data());
+    } else {
+      targets_ = new (zone) CallTargets(zone);
+      ASSERT(targets_->is_empty());
+    }
+  }
+  return *targets_;
+}
+
+const BinaryFeedback& InstanceCallInstr::BinaryFeedback() {
+  if (binary_ == nullptr) {
+    Zone* zone = Thread::Current()->zone();
+    if (HasICData()) {
+      binary_ = BinaryFeedback::Create(zone, *ic_data());
+    } else {
+      binary_ = new (zone) class BinaryFeedback(zone);
+    }
+  }
+  return *binary_;
+}
+
+const CallTargets& StaticCallInstr::Targets() {
+  if (targets_ == nullptr) {
+    Zone* zone = Thread::Current()->zone();
+    if (HasICData()) {
+      targets_ = CallTargets::CreateAndExpand(zone, *ic_data());
+    } else {
+      targets_ = new (zone) CallTargets(zone);
+      ASSERT(targets_->is_empty());
+    }
+  }
+  return *targets_;
+}
+
+const BinaryFeedback& StaticCallInstr::BinaryFeedback() {
+  if (binary_ == nullptr) {
+    Zone* zone = Thread::Current()->zone();
+    if (HasICData()) {
+      binary_ = BinaryFeedback::Create(zone, *ic_data());
+    } else {
+      binary_ = new (zone) class BinaryFeedback(zone);
+    }
+  }
+  return *binary_;
+}
+
 bool CallTargets::HasSingleRecognizedTarget() const {
   if (!HasSingleTarget()) return false;
   return MethodRecognizer::RecognizeKind(FirstTarget()) !=
@@ -4499,7 +4606,7 @@
 }
 
 bool CallTargets::HasSingleTarget() const {
-  ASSERT(length() != 0);
+  if (length() == 0) return false;
   for (int i = 0; i < length(); i++) {
     if (TargetAt(i)->target->raw() != TargetAt(0)->target->raw()) return false;
   }
@@ -4604,7 +4711,7 @@
   // TODO(dartbug.com/37291): Allow this optimization, but accumulate affected
   // InstanceCallInstrs and the corresponding reciever cids during compilation.
   // After compilation, add receiver checks to the ICData for those call sites.
-  if (ic_data()->NumberOfUsedChecks() == 0) return this;
+  if (Targets().is_empty()) return this;
 
   const CallTargets* new_target =
       FlowGraphCompiler::ResolveCallTargetsForReceiverCid(
@@ -4985,6 +5092,10 @@
       EmitLoadFromBox(compiler);
     } else if (CanConvertSmi() && (value_cid == kSmiCid)) {
       EmitSmiConversion(compiler);
+    } else if (representation() == kUnboxedInt32 && value()->Type()->IsInt()) {
+      EmitLoadInt32FromBoxOrSmi(compiler);
+    } else if (representation() == kUnboxedInt64 && value()->Type()->IsInt()) {
+      EmitLoadInt64FromBoxOrSmi(compiler);
     } else {
       ASSERT(CanDeoptimize());
       EmitLoadFromBoxWithDeopt(compiler);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index ada13c7..fb2fc75 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_COMPILER_BACKEND_IL_H_
 #define RUNTIME_VM_COMPILER_BACKEND_IL_H_
 
+#include <utility>
+
 #include "vm/allocation.h"
 #include "vm/code_descriptors.h"
 #include "vm/compiler/backend/compile_type.h"
@@ -24,6 +26,7 @@
 
 namespace dart {
 
+class BinaryFeedback;
 class BitVector;
 class BlockEntryInstr;
 class BlockEntryWithInitialDefs;
@@ -46,10 +49,10 @@
 class Range;
 class RangeAnalysis;
 class RangeBoundary;
-class SExpression;
 class SExpList;
-class UnboxIntegerInstr;
+class SExpression;
 class TypeUsageInfo;
+class UnboxIntegerInstr;
 
 namespace compiler {
 class BlockBuilder;
@@ -573,14 +576,14 @@
 // and PolymorphicInstanceCall instructions.
 class Cids : public ZoneAllocated {
  public:
-  explicit Cids(Zone* zone) : zone_(zone) {}
+  explicit Cids(Zone* zone) : cid_ranges_(zone, 6) {}
   // Creates the off-heap Cids object that reflects the contents
   // of the on-VM-heap IC data.
   // Ranges of Cids are merged if there is only one target function and
   // it is used for all cids in the gaps between ranges.
-  static Cids* CreateAndExpand(Zone* zone,
-                               const ICData& ic_data,
-                               int argument_number);
+  static Cids* CreateForArgument(Zone* zone,
+                                 const BinaryFeedback& binary_feedback,
+                                 int argument_number);
   static Cids* CreateMonomorphic(Zone* zone, intptr_t cid);
 
   bool Equals(const Cids& other) const;
@@ -609,12 +612,7 @@
   intptr_t ComputeHighestCid() const;
 
  protected:
-  void CreateHelper(Zone* zone,
-                    const ICData& ic_data,
-                    int argument_number,
-                    bool include_targets);
   GrowableArray<CidRange*> cid_ranges_;
-  Zone* zone_;
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Cids);
@@ -623,18 +621,24 @@
 class CallTargets : public Cids {
  public:
   explicit CallTargets(Zone* zone) : Cids(zone) {}
+
+  static const CallTargets* CreateMonomorphic(Zone* zone,
+                                              intptr_t receiver_cid,
+                                              const Function& target);
+
   // Creates the off-heap CallTargets object that reflects the contents
   // of the on-VM-heap IC data.
-  static CallTargets* Create(Zone* zone, const ICData& ic_data);
+  static const CallTargets* Create(Zone* zone, const ICData& ic_data);
 
   // This variant also expands the class-ids to neighbouring classes that
   // inherit the same method.
-  static CallTargets* CreateAndExpand(Zone* zone, const ICData& ic_data);
+  static const CallTargets* CreateAndExpand(Zone* zone, const ICData& ic_data);
 
   TargetInfo* TargetAt(int i) const { return static_cast<TargetInfo*>(At(i)); }
 
   intptr_t AggregateCallCount() const;
 
+  StaticTypeExactnessState MonomorphicExactness() const;
   bool HasSingleTarget() const;
   bool HasSingleRecognizedTarget() const;
   const Function& FirstTarget() const;
@@ -642,10 +646,96 @@
 
   void Print() const;
 
+  bool ReceiverIs(intptr_t cid) const {
+    return IsMonomorphic() && MonomorphicReceiverCid() == cid;
+  }
+  bool ReceiverIsSmiOrMint() const {
+    if (cid_ranges_.is_empty()) {
+      return false;
+    }
+    for (intptr_t i = 0, n = cid_ranges_.length(); i < n; i++) {
+      for (intptr_t j = cid_ranges_[i]->cid_start; j <= cid_ranges_[i]->cid_end;
+           j++) {
+        if (j != kSmiCid && j != kMintCid) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
  private:
+  void CreateHelper(Zone* zone, const ICData& ic_data);
   void MergeIntoRanges();
 };
 
+// Represents type feedback for the binary operators, and a few recognized
+// static functions (see MethodRecognizer::NumArgsCheckedForStaticCall).
+class BinaryFeedback : public ZoneAllocated {
+ public:
+  explicit BinaryFeedback(Zone* zone) : feedback_(zone, 2) {}
+
+  static const BinaryFeedback* Create(Zone* zone, const ICData& ic_data);
+  static const BinaryFeedback* CreateMonomorphic(Zone* zone,
+                                                 intptr_t receiver_cid,
+                                                 intptr_t argument_cid);
+
+  bool ArgumentIs(intptr_t cid) const {
+    if (feedback_.is_empty()) {
+      return false;
+    }
+    for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+      if (feedback_[i].second != cid) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool OperandsAreEither(intptr_t cid_a, intptr_t cid_b) const {
+    if (feedback_.is_empty()) {
+      return false;
+    }
+    for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+      if ((feedback_[i].first != cid_a) && (feedback_[i].first != cid_b)) {
+        return false;
+      }
+      if ((feedback_[i].second != cid_a) && (feedback_[i].second != cid_b)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  bool OperandsAreSmiOrNull() const {
+    return OperandsAreEither(kSmiCid, kNullCid);
+  }
+  bool OperandsAreSmiOrMint() const {
+    return OperandsAreEither(kSmiCid, kMintCid);
+  }
+  bool OperandsAreSmiOrDouble() const {
+    return OperandsAreEither(kSmiCid, kDoubleCid);
+  }
+
+  bool OperandsAre(intptr_t cid) const {
+    if (feedback_.length() != 1) return false;
+    return (feedback_[0].first == cid) && (feedback_[0].second == cid);
+  }
+
+  bool IncludesOperands(intptr_t cid) const {
+    for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+      if ((feedback_[i].first == cid) && (feedback_[i].second == cid)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+ private:
+  GrowableArray<std::pair<intptr_t, intptr_t>> feedback_;
+
+  friend class Cids;
+};
+
 class Instruction : public ZoneAllocated {
  public:
 #define DECLARE_TAG(type, attrs) k##type,
@@ -1319,6 +1409,8 @@
                              BitVector* block_marks);
 
  private:
+  friend class FlowGraphDeserializer;  // Access to AddPredecessor().
+
   virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
 
   virtual void ClearPredecessors() = 0;
@@ -1506,6 +1598,12 @@
   PRINT_TO_SUPPORT
 
  private:
+  friend class FlowGraphDeserializer;  // For the constructor with deopt_id arg.
+
+  GraphEntryInstr(const ParsedFunction& parsed_function,
+                  intptr_t osr_id,
+                  intptr_t deopt_id);
+
   virtual void ClearPredecessors() {}
   virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
 
@@ -1904,10 +2002,7 @@
   explicit Definition(intptr_t deopt_id = DeoptId::kNone);
 
   // Overridden by definitions that have call counts.
-  virtual intptr_t CallCount() const {
-    UNREACHABLE();
-    return -1;
-  }
+  virtual intptr_t CallCount() const { return -1; }
 
   intptr_t temp_index() const { return temp_index_; }
   void set_temp_index(intptr_t index) { temp_index_ = index; }
@@ -3272,13 +3367,25 @@
 // the type arguments of a generic function or an arguments descriptor.
 class SpecialParameterInstr : public TemplateDefinition<0, NoThrow> {
  public:
-  enum SpecialParameterKind {
-    kContext,
-    kTypeArgs,
-    kArgDescriptor,
-    kException,
-    kStackTrace
-  };
+#define FOR_EACH_SPECIAL_PARAMETER_KIND(M)                                     \
+  M(Context)                                                                   \
+  M(TypeArgs)                                                                  \
+  M(ArgDescriptor)                                                             \
+  M(Exception)                                                                 \
+  M(StackTrace)
+
+#define KIND_DECL(name) k##name,
+  enum SpecialParameterKind { FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_DECL) };
+#undef KIND_DECL
+
+  // Defined as a static intptr_t instead of inside the enum since some
+  // switch statements depend on the exhaustibility checking.
+#define KIND_INC(name) +1
+  static const intptr_t kNumKinds = 0 FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_INC);
+#undef KIND_INC
+
+  static const char* KindToCString(SpecialParameterKind k);
+  static bool KindFromCString(const char* str, SpecialParameterKind* out);
 
   SpecialParameterInstr(SpecialParameterKind kind,
                         intptr_t deopt_id,
@@ -3305,23 +3412,6 @@
   PRINT_OPERANDS_TO_SUPPORT
   ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
 
-  static const char* KindToCString(SpecialParameterKind kind) {
-    switch (kind) {
-      case kContext:
-        return "kContext";
-      case kTypeArgs:
-        return "kTypeArgs";
-      case kArgDescriptor:
-        return "kArgDescriptor";
-      case kException:
-        return "kException";
-      case kStackTrace:
-        return "kStackTrace";
-    }
-    UNREACHABLE();
-    return NULL;
-  }
-
  private:
   const SpecialParameterKind kind_;
   BlockEntryInstr* block_;
@@ -3440,6 +3530,7 @@
   Code::EntryKind entry_kind() const { return entry_kind_; }
 
   PRINT_OPERANDS_TO_SUPPORT
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
 
  private:
   const Code::EntryKind entry_kind_;
@@ -3584,12 +3675,22 @@
 
   void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
 
+  const CallTargets& Targets();
+  void SetTargets(const CallTargets* targets) { targets_ = targets; }
+
+  const BinaryFeedback& BinaryFeedback();
+  void SetBinaryFeedback(const class BinaryFeedback* binary) {
+    binary_ = binary;
+  }
+
  protected:
   friend class CallSpecializer;
   void set_ic_data(ICData* value) { ic_data_ = value; }
 
  private:
   const ICData* ic_data_;
+  const CallTargets* targets_ = nullptr;
+  const class BinaryFeedback* binary_ = nullptr;
   const String& function_name_;
   const Token::Kind token_kind_;  // Binary op, unary op, kGET or kILLEGAL.
   const intptr_t checked_argument_count_;
@@ -3713,6 +3814,7 @@
   bool AttributesEqual(Instruction* other) const;
 
   PRINT_OPERANDS_TO_SUPPORT
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT;
 
  private:
   // True if the comparison must check for double or Mint and
@@ -4107,11 +4209,17 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  const CallTargets& Targets();
+  const BinaryFeedback& BinaryFeedback();
+
   PRINT_OPERANDS_TO_SUPPORT
   ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
 
  private:
   const ICData* ic_data_;
+  const CallTargets* targets_ = nullptr;
+  const class BinaryFeedback* binary_ = nullptr;
   const intptr_t call_count_;
   const Function& function_;
   const ICData::RebindRule rebind_rule_;
@@ -4190,10 +4298,7 @@
     return false;
   }
 
-  virtual bool MayThrow() const {
-    UNREACHABLE();
-    return false;
-  }
+  virtual bool MayThrow() const { return false; }
 
   virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
 
@@ -4238,10 +4343,7 @@
     return false;
   }
 
-  virtual bool MayThrow() const {
-    UNREACHABLE();
-    return false;
-  }
+  virtual bool MayThrow() const { return false; }
 
   virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
 
@@ -4445,6 +4547,8 @@
   virtual bool HasUnknownSideEffects() const { return true; }
   virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const RawPcDescriptors::Kind stub_kind_;
@@ -4561,6 +4665,7 @@
 
   PRINT_OPERANDS_TO_SUPPORT
   ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
 
  private:
   friend class JitCallSpecializer;  // For ASSERT(initialization_).
@@ -7641,8 +7746,9 @@
   virtual bool RecomputeType();
 
   // CheckNull can implicitly call Dart code (NoSuchMethodError constructor),
-  // so it can lazily deopt.
+  // so it needs a deopt ID in optimized and unoptimized code.
   virtual bool ComputeCanDeoptimize() const { return true; }
+  virtual bool CanBecomeDeoptimizationTarget() const { return true; }
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
@@ -7653,6 +7759,8 @@
 
   virtual Value* RedefinedValue() const;
 
+  ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const String& function_name_;
@@ -8454,6 +8562,7 @@
  private:
   friend class ShallowIterator;
   friend class compiler::BlockBuilder;  // For Environment constructor.
+  friend class FlowGraphDeserializer;   // For constructor and deopt_id_.
 
   Environment(intptr_t length,
               intptr_t fixed_parameter_count,
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index e747e3e..6f00a18 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1137,10 +1137,6 @@
 }
 
 void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (FLAG_precompiled_mode) {
-    UNREACHABLE();
-  }
-
   // Constant pool cannot be used until we enter the actual Dart frame.
   __ set_constant_pool_allowed(false);
 
@@ -1165,8 +1161,41 @@
 
   // Load the thread object. If we were called by a trampoline, the thread is
   // already loaded.
-  //
-  // TODO(35765): Fix linking issue on AOT.
+  if (FLAG_precompiled_mode) {
+    compiler::Label skip_reloc;
+    __ b(&skip_reloc);
+    compiler->InsertBSSRelocation(
+        BSS::Relocation::DRT_GetThreadForNativeCallback);
+    __ Bind(&skip_reloc);
+
+    // For historical reasons, the PC on ARM points 8 bytes (two instructions)
+    // past the current instruction.
+    __ sub(
+        R0, PC,
+        compiler::Operand(Instr::kPCReadOffset + compiler::target::kWordSize));
+
+    // R0 holds the address of the relocation.
+    __ ldr(R1, compiler::Address(R0));
+
+    // R1 holds the relocation itself: R0 - bss_start.
+    // R0 = R0 + (bss_start - R0) = bss_start
+    __ add(R0, R0, compiler::Operand(R1));
+
+    // R0 holds the start of the BSS section.
+    // Load the "get-thread" routine: *bss_start.
+    __ ldr(R1, compiler::Address(R0));
+  } else if (!NativeCallbackTrampolines::Enabled()) {
+    // In JIT mode, we can just paste the address of the runtime entry into the
+    // generated code directly. This is not a problem since we don't save
+    // callbacks into JIT snapshots.
+    ASSERT(kWordSize == compiler::target::kWordSize);
+    __ LoadImmediate(
+        R1, static_cast<compiler::target::uword>(
+                reinterpret_cast<uword>(DLRT_GetThreadForNativeCallback)));
+  }
+
+  // Load the thread object. If we were called by a trampoline, the thread is
+  // already loaded.
   if (!NativeCallbackTrampolines::Enabled()) {
     // Create another frame to align the frame before continuing in "native"
     // code.
@@ -1174,8 +1203,6 @@
     __ ReserveAlignedFrameSpace(0);
 
     __ LoadImmediate(R0, callback_id_);
-    __ LoadImmediate(
-        R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
     __ blx(R1);
     __ mov(THR, compiler::Operand(R0));
 
@@ -6954,7 +6981,8 @@
       break;
     case kUnboxedFloat:
     case kUnboxedDouble:
-      summary->set_in(0, Location::RequiresFpuRegister());
+      // Choose an FPU register with corresponding D and S registers.
+      summary->set_in(0, Location::FpuRegisterLocation(Q0));
       break;
     default:
       UNREACHABLE();
@@ -6970,7 +6998,8 @@
       break;
     case kUnboxedFloat:
     case kUnboxedDouble:
-      summary->set_out(0, Location::RequiresFpuRegister());
+      // Choose an FPU register with corresponding D and S registers.
+      summary->set_out(0, Location::FpuRegisterLocation(Q0));
       break;
     default:
       UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index ced71dd..b49dc6e 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1020,10 +1020,6 @@
 }
 
 void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (FLAG_precompiled_mode) {
-    UNREACHABLE();
-  }
-
   // Constant pool cannot be used until we enter the actual Dart frame.
   __ set_constant_pool_allowed(false);
 
@@ -1052,8 +1048,33 @@
 
   // Load the thread object. If we were called by a trampoline, the thread is
   // already loaded.
-  //
-  // TODO(35765): Fix linking issue on AOT.
+  if (FLAG_precompiled_mode) {
+    compiler::Label skip_reloc;
+    __ b(&skip_reloc);
+    compiler->InsertBSSRelocation(
+        BSS::Relocation::DRT_GetThreadForNativeCallback);
+    __ Bind(&skip_reloc);
+
+    __ adr(R0, compiler::Immediate(-compiler::target::kWordSize));
+
+    // R0 holds the address of the relocation.
+    __ ldr(R1, compiler::Address(R0));
+
+    // R1 holds the relocation itself: R0 - bss_start.
+    // R0 = R0 + (bss_start - R0) = bss_start
+    __ add(R0, R0, compiler::Operand(R1));
+
+    // R0 holds the start of the BSS section.
+    // Load the "get-thread" routine: *bss_start.
+    __ ldr(R1, compiler::Address(R0));
+  } else if (!NativeCallbackTrampolines::Enabled()) {
+    // In JIT mode, we can just paste the address of the runtime entry into the
+    // generated code directly. This is not a problem since we don't save
+    // callbacks into JIT snapshots.
+    __ LoadImmediate(
+        R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
+  }
+
   if (!NativeCallbackTrampolines::Enabled()) {
     // Create another frame to align the frame before continuing in "native"
     // code.
@@ -1061,8 +1082,6 @@
     __ ReserveAlignedFrameSpace(0);
 
     __ LoadImmediate(R0, callback_id_);
-    __ LoadImmediate(
-        R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
     __ blr(R1);
     __ mov(THR, R0);
 
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
new file mode 100644
index 0000000..f4bf535
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -0,0 +1,1760 @@
+// 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.
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+#include "vm/compiler/backend/il_deserializer.h"
+
+#include "vm/compiler/backend/il_serializer.h"
+#include "vm/compiler/jit/compiler.h"
+#include "vm/flags.h"
+#include "vm/os.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool,
+            trace_round_trip_serialization,
+            false,
+            "Print out tracing information during round trip serialization.");
+DEFINE_FLAG(bool,
+            print_json_round_trip_results,
+            false,
+            "Print out results of each round trip serialization in JSON form.");
+
+// Contains the contents of a single round-trip result.
+struct RoundTripResults : public ValueObject {
+  explicit RoundTripResults(Zone* zone, const Function& func)
+      : function(func), unhandled(zone, 2) {}
+
+  // The function for which a flow graph was being parsed.
+  const Function& function;
+  // Whether the round trip succeeded.
+  bool success = false;
+  // An array of unhandled instructions found in the flow graph.
+  GrowableArray<Instruction*> unhandled;
+  // The serialized form of the flow graph, if computed.
+  SExpression* serialized = nullptr;
+  // The error information from the deserializer, if an error occurred.
+  const char* error_message = nullptr;
+  SExpression* error_sexp = nullptr;
+};
+
+static void PrintRoundTripResults(Zone* zone, const RoundTripResults& results) {
+  THR_Print("Results of round trip serialization: {\"function\":\"%s\"",
+            results.function.ToFullyQualifiedCString());
+  THR_Print(",\"success\":%s", results.success ? "true" : "false");
+  if (!results.unhandled.is_empty()) {
+    CStringMap<intptr_t> count_map(zone);
+    for (auto inst : results.unhandled) {
+      auto const name = inst->DebugName();
+      auto const old_count = count_map.LookupValue(name);
+      count_map.Update({name, old_count + 1});
+    }
+    THR_Print(",\"unhandled\":{");
+    auto count_it = count_map.GetIterator();
+    auto first_kv = count_it.Next();
+    THR_Print("\"%s\":%" Pd "", first_kv->key, first_kv->value);
+    while (auto kv = count_it.Next()) {
+      THR_Print(",\"%s\":%" Pd "", kv->key, kv->value);
+    }
+    THR_Print("}");
+  }
+  if (results.serialized != nullptr) {
+    TextBuffer buf(1000);
+    results.serialized->SerializeTo(zone, &buf, "");
+    // Now that the S-expression has been serialized to the TextBuffer, we now
+    // want to take that version and escape it since we will use it as the
+    // contents of a JSON string. Thankfully, escaping can be done via
+    // TextBuffer::AddEscapedString, so we steal the current buffer and then
+    // re-print it in escaped form into the now-cleared buffer.
+    char* const unescaped_sexp = buf.Steal();
+    buf.AddEscapedString(unescaped_sexp);
+    free(unescaped_sexp);
+    THR_Print(",\"serialized\":\"%s\"", buf.buf());
+  }
+  if (results.error_message != nullptr) {
+    TextBuffer buf(1000);
+    ASSERT(results.error_sexp != nullptr);
+    // Same serialized S-expression juggling as in the results.serialized case.
+    // We also escape the error message, in case it included quotes.
+    buf.AddEscapedString(results.error_message);
+    char* const escaped_message = buf.Steal();
+    results.error_sexp->SerializeTo(zone, &buf, "");
+    char* const unescaped_sexp = buf.Steal();
+    buf.AddEscapedString(unescaped_sexp);
+    free(unescaped_sexp);
+    THR_Print(",\"error\":{\"message\":\"%s\",\"expression\":\"%s\"}",
+              escaped_message, buf.buf());
+    free(escaped_message);
+  }
+  THR_Print("}\n");
+}
+
+void FlowGraphDeserializer::RoundTripSerialization(CompilerPassState* state) {
+  auto const flow_graph = state->flow_graph;
+
+  // The deserialized flow graph must be in the same zone as the original flow
+  // graph, to ensure it has the right lifetime. Thus, we leave an explicit
+  // use of [flow_graph->zone()] in the deserializer construction.
+  //
+  // Otherwise, it would be nice to use a StackZone to limit the lifetime of the
+  // serialized form (and other values created with this [zone] variable), since
+  // it only needs to live for the dynamic extent of this method.
+  //
+  // However, creating a StackZone for it also changes the zone associated with
+  // the thread. Also, some parts of the VM used in later updates to the
+  // deserializer implicitly pick up the zone to use either from a passed-in
+  // thread or the current thread instead of taking an explicit zone.
+  //
+  // For now, just serialize into the same zone as the original flow graph, and
+  // we can revisit this if this causes a performance issue or if we can ensure
+  // that those VM parts mentioned can be passed an explicit zone.
+  Zone* const zone = flow_graph->zone();
+
+  // Final flow graph, if we successfully serialize and deserialize.
+  FlowGraph* new_graph = nullptr;
+
+  // Stored information for printing results if requested.
+  RoundTripResults results(zone, flow_graph->function());
+
+  FlowGraphDeserializer::AllUnhandledInstructions(flow_graph,
+                                                  &results.unhandled);
+  if (results.unhandled.is_empty()) {
+    results.serialized = FlowGraphSerializer::SerializeToSExp(zone, flow_graph);
+
+    if (FLAG_trace_round_trip_serialization && results.serialized != nullptr) {
+      TextBuffer buf(1000);
+      results.serialized->SerializeTo(zone, &buf, "");
+      THR_Print("Serialized flow graph:\n%s\n", buf.buf());
+    }
+
+    // For the deserializer, use the thread from the compiler pass and zone
+    // associated with the existing flow graph to make sure the new flow graph
+    // has the right lifetime.
+    FlowGraphDeserializer d(state->thread, flow_graph->zone(),
+                            results.serialized, &flow_graph->parsed_function());
+    new_graph = d.ParseFlowGraph();
+    if (new_graph == nullptr) {
+      ASSERT(d.error_message() != nullptr && d.error_sexp() != nullptr);
+      if (FLAG_trace_round_trip_serialization) {
+        THR_Print("Failure during deserialization: %s\n", d.error_message());
+        THR_Print("At S-expression %s\n", d.error_sexp()->ToCString(zone));
+      }
+      results.error_message = d.error_message();
+      results.error_sexp = d.error_sexp();
+    } else {
+      if (FLAG_trace_round_trip_serialization) {
+        THR_Print("Successfully deserialized graph for %s\n",
+                  results.serialized->AsList()->At(0)->AsSymbol()->value());
+      }
+      results.success = true;
+    }
+  } else if (FLAG_trace_round_trip_serialization) {
+    THR_Print("Cannot serialize graph due to instruction: %s\n",
+              results.unhandled.At(0)->DebugName());
+  }
+
+  if (FLAG_print_json_round_trip_results) PrintRoundTripResults(zone, results);
+
+  if (new_graph != nullptr) state->flow_graph = new_graph;
+}
+
+#define HANDLED_CASE(name)                                                     \
+  if (inst->Is##name()) return true;
+bool FlowGraphDeserializer::IsHandledInstruction(Instruction* inst) {
+  if (auto const const_inst = inst->AsConstant()) {
+    return IsHandledConstant(const_inst->value());
+  }
+  FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLED_CASE)
+  FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_CASE)
+  return false;
+}
+#undef HANDLED_CASE
+
+void FlowGraphDeserializer::AllUnhandledInstructions(
+    const FlowGraph* graph,
+    GrowableArray<Instruction*>* unhandled) {
+  ASSERT(graph != nullptr);
+  ASSERT(unhandled != nullptr);
+  for (auto block_it = graph->reverse_postorder_iterator(); !block_it.Done();
+       block_it.Advance()) {
+    auto const entry = block_it.Current();
+    if (!IsHandledInstruction(entry)) unhandled->Add(entry);
+    // Don't check the Phi definitions in JoinEntrys, as those are now handled
+    // and also parsed differently from other definitions.
+    if (auto const def_block = entry->AsBlockEntryWithInitialDefs()) {
+      auto const defs = def_block->initial_definitions();
+      for (intptr_t i = 0; i < defs->length(); i++) {
+        auto const current = defs->At(i);
+        if (!IsHandledInstruction(current)) unhandled->Add(current);
+      }
+    }
+    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+      auto current = it.Current();
+      // We handle branches, so we need to check the comparison instruction.
+      if (current->IsBranch()) current = current->AsBranch()->comparison();
+      if (!IsHandledInstruction(current)) unhandled->Add(current);
+    }
+  }
+}
+
+// Keep in sync with work in ParseDartValue. Right now, this is just a shallow
+// check, not a deep one.
+bool FlowGraphDeserializer::IsHandledConstant(const Object& obj) {
+  if (obj.IsArray()) return Array::Cast(obj).IsImmutable();
+  return obj.IsNull() || obj.IsClass() || obj.IsFunction() || obj.IsField() ||
+         obj.IsInstance();
+}
+
+SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, intptr_t index) {
+  if (list == nullptr) return nullptr;
+  if (list->Length() <= index) {
+    StoreError(list, "expected at least %" Pd " element(s) in list", index + 1);
+    return nullptr;
+  }
+  auto const elem = list->At(index);
+  if (elem == nullptr) {
+    StoreError(list, "null value at index %" Pd "", index);
+  }
+  return elem;
+}
+
+SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, const char* key) {
+  if (list == nullptr) return nullptr;
+  if (!list->ExtraHasKey(key)) {
+    StoreError(list, "expected an extra info entry for key %s", key);
+    return nullptr;
+  }
+  auto const elem = list->ExtraLookupValue(key);
+  if (elem == nullptr) {
+    StoreError(list, "null value for key %s", key);
+  }
+  return elem;
+}
+
+FlowGraph* FlowGraphDeserializer::ParseFlowGraph() {
+  auto const root = CheckTaggedList(root_sexp_, "FlowGraph");
+  if (root == nullptr) return nullptr;
+
+  intptr_t deopt_id = DeoptId::kNone;
+  if (auto const deopt_id_sexp =
+          CheckInteger(root->ExtraLookupValue("deopt_id"))) {
+    deopt_id = deopt_id_sexp->value();
+  }
+  EntryInfo common_info = {0, kInvalidTryIndex, deopt_id};
+
+  auto const graph = DeserializeGraphEntry(root, common_info);
+
+  PrologueInfo pi(-1, -1);
+  flow_graph_ = new (zone()) FlowGraph(*parsed_function_, graph, 0, pi);
+  flow_graph_->CreateCommonConstants();
+
+  intptr_t pos = 2;
+  if (auto const pool = CheckTaggedList(Retrieve(root, pos), "Constants")) {
+    if (!ParseConstantPool(pool)) return nullptr;
+    pos++;
+  }
+
+  // The deopt environment for the graph entry may use entries from the
+  // constant pool, so that must be parsed first.
+  if (auto const env_sexp = CheckList(root->ExtraLookupValue("env"))) {
+    auto const env = ParseEnvironment(env_sexp);
+    if (env == nullptr) return nullptr;
+    env->DeepCopyTo(zone(), graph);
+  }
+
+  auto const entries_sexp = CheckTaggedList(Retrieve(root, pos), "Entries");
+  if (!ParseEntries(entries_sexp)) return nullptr;
+  pos++;
+
+  // Now prime the block worklist with entries. We keep the block worklist
+  // in reverse order so that we can just pop the next block for content
+  // parsing off the end.
+  BlockWorklist block_worklist(zone(), entries_sexp->Length() - 1);
+
+  const auto& indirect_entries = graph->indirect_entries();
+  for (auto indirect_entry : indirect_entries) {
+    block_worklist.Add(indirect_entry->block_id());
+  }
+
+  const auto& catch_entries = graph->catch_entries();
+  for (auto catch_entry : catch_entries) {
+    block_worklist.Add(catch_entry->block_id());
+  }
+
+  if (auto const osr_entry = graph->osr_entry()) {
+    block_worklist.Add(osr_entry->block_id());
+  }
+  if (auto const unchecked_entry = graph->unchecked_entry()) {
+    block_worklist.Add(unchecked_entry->block_id());
+  }
+  if (auto const normal_entry = graph->normal_entry()) {
+    block_worklist.Add(normal_entry->block_id());
+  }
+
+  // The graph entry doesn't push any arguments onto the stack. Adding a
+  // pushed_stack_map_ entry for it allows us to unify how function entries
+  // are handled vs. other types of blocks with regards to incoming pushed
+  // argument stacks.
+  auto const empty_stack = new (zone()) PushStack(zone(), 0);
+  pushed_stack_map_.Insert(0, empty_stack);
+
+  if (!ParseBlocks(root, pos, &block_worklist)) return nullptr;
+
+  // Before we return the new graph, make sure all definitions were found for
+  // all pending values.
+  if (values_map_.Length() > 0) {
+    auto it = values_map_.GetIterator();
+    auto const kv = it.Next();
+    // TODO(sstrickl): This assumes SSA variables.
+    auto const sym =
+        new (zone()) SExpSymbol(OS::SCreate(zone(), "v%" Pd "", kv->key));
+    StoreError(sym, "no definition found for variable index in flow graph");
+    return nullptr;
+  }
+
+  flow_graph_->set_max_block_id(max_block_id_);
+  flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 1);
+  // Now that the deserializer has finished re-creating all the blocks in the
+  // flow graph, the blocks must be rediscovered. In addition, if ComputeSSA
+  // has already been run, dominators must be recomputed as well.
+  flow_graph_->DiscoverBlocks();
+  // Currently we only handle SSA graphs, so always do this.
+  GrowableArray<BitVector*> dominance_frontier;
+  flow_graph_->ComputeDominators(&dominance_frontier);
+
+  return flow_graph_;
+}
+
+bool FlowGraphDeserializer::ParseConstantPool(SExpList* pool) {
+  ASSERT(flow_graph_ != nullptr);
+  if (pool == nullptr) return false;
+  // Definitions in the constant pool may refer to later definitions. However,
+  // there should be no cycles possible between constant objects, so using a
+  // worklist algorithm we should always be able to make progress.
+  // Since we will not be adding new definitions, we make the initial size of
+  // the worklist the number of definitions in the constant pool.
+  GrowableArray<SExpList*> worklist(zone(), pool->Length() - 1);
+  // We keep old_worklist in reverse order so that we can just RemoveLast
+  // to get elements in their original order.
+  for (intptr_t i = pool->Length() - 1; i > 0; i--) {
+    const auto def_sexp = CheckTaggedList(pool->At(i), "def");
+    if (def_sexp == nullptr) return false;
+    worklist.Add(def_sexp);
+  }
+  while (true) {
+    const intptr_t worklist_len = worklist.length();
+    GrowableArray<SExpList*> parse_failures(zone(), worklist_len);
+    while (!worklist.is_empty()) {
+      const auto def_sexp = worklist.RemoveLast();
+      auto& obj = Object::ZoneHandle(zone());
+      if (!ParseDartValue(Retrieve(def_sexp, 2), &obj)) {
+        parse_failures.Add(def_sexp);
+        continue;
+      }
+      ConstantInstr* def = flow_graph_->GetConstant(obj);
+      if (!ParseDefinitionWithParsedBody(def_sexp, def)) return false;
+    }
+    if (parse_failures.is_empty()) break;
+    // We've gone through the whole worklist without success, so return
+    // the last error we encountered.
+    if (parse_failures.length() == worklist_len) return false;
+    // worklist was added to in order, so we need to reverse its contents
+    // when we add them to old_worklist.
+    while (!parse_failures.is_empty()) {
+      worklist.Add(parse_failures.RemoveLast());
+    }
+  }
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseEntries(SExpList* list) {
+  ASSERT(flow_graph_ != nullptr);
+  if (list == nullptr) return false;
+  for (intptr_t i = 1; i < list->Length(); i++) {
+    const auto entry = CheckTaggedList(Retrieve(list, i));
+    if (entry == nullptr) return false;
+    intptr_t block_id;
+    if (!ParseBlockId(CheckSymbol(Retrieve(entry, 1)), &block_id)) {
+      return false;
+    }
+    if (block_map_.LookupValue(block_id) != nullptr) {
+      StoreError(entry->At(1), "multiple entries for block found");
+      return false;
+    }
+    const auto tag = entry->At(0)->AsSymbol();
+    if (ParseBlockHeader(entry, block_id, tag) == nullptr) return false;
+  }
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseBlocks(SExpList* list,
+                                        intptr_t pos,
+                                        BlockWorklist* worklist) {
+  // First, ensure that all the block headers have been parsed. Set up a
+  // map from block IDs to S-expressions and the max_block_id while we're at it.
+  IntMap<SExpList*> block_sexp_map(zone());
+  for (intptr_t i = pos, n = list->Length(); i < n; i++) {
+    auto const block_sexp = CheckTaggedList(Retrieve(list, i), "Block");
+    intptr_t block_id;
+    if (!ParseBlockId(CheckSymbol(Retrieve(block_sexp, 1)), &block_id)) {
+      return false;
+    }
+    if (block_sexp_map.LookupValue(block_id) != nullptr) {
+      StoreError(block_sexp->At(1), "multiple definitions of block found");
+      return false;
+    }
+    block_sexp_map.Insert(block_id, block_sexp);
+    auto const type_tag =
+        CheckSymbol(block_sexp->ExtraLookupValue("block_type"));
+    // Entry block headers are already parsed, but others aren't.
+    if (block_map_.LookupValue(block_id) == nullptr) {
+      if (ParseBlockHeader(block_sexp, block_id, type_tag) == nullptr) {
+        return false;
+      }
+    }
+    if (max_block_id_ < block_id) max_block_id_ = block_id;
+  }
+
+  // Now start parsing the contents of blocks from the worklist. We use an
+  // IntMap to keep track of what blocks have already been fully parsed.
+  IntMap<bool> fully_parsed_block_map(zone());
+  while (!worklist->is_empty()) {
+    auto const block_id = worklist->RemoveLast();
+
+    // If we've already encountered this block, skip it.
+    if (fully_parsed_block_map.LookupValue(block_id)) continue;
+
+    auto const block_sexp = block_sexp_map.LookupValue(block_id);
+    ASSERT(block_sexp != nullptr);
+
+    // Copy the pushed argument stack of the predecessor to begin the stack for
+    // this block. This is safe due to the worklist algorithm, since one
+    // predecessor has already been added when this block is first reached.
+    //
+    // For JoinEntry blocks, since the worklist algorithm is a depth-first
+    // search, we may not see all possible predecessors before the JoinEntry
+    // is parsed. To ensure consistency between predecessor stacks, we check
+    // the consistency in ParseBlockContents when updating predecessor
+    // information.
+    current_block_ = block_map_.LookupValue(block_id);
+    ASSERT(current_block_ != nullptr);
+    ASSERT(current_block_->PredecessorCount() > 0);
+    auto const pred_id = current_block_->PredecessorAt(0)->block_id();
+    auto const pred_stack = pushed_stack_map_.LookupValue(pred_id);
+    ASSERT(pred_stack != nullptr);
+    auto const new_stack = new (zone()) PushStack(zone(), pred_stack->length());
+    new_stack->AddArray(*pred_stack);
+    pushed_stack_map_.Insert(block_id, new_stack);
+
+    if (!ParseBlockContents(block_sexp, worklist)) return false;
+
+    // Mark this block as done.
+    fully_parsed_block_map.Insert(block_id, true);
+  }
+
+  // Double-check that all blocks were reached by the worklist algorithm.
+  auto it = block_sexp_map.GetIterator();
+  while (auto kv = it.Next()) {
+    if (!fully_parsed_block_map.LookupValue(kv->key)) {
+      StoreError(kv->value, "block unreachable in flow graph");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseInitialDefinitions(SExpList* list) {
+  ASSERT(current_block_ != nullptr);
+  ASSERT(current_block_->IsBlockEntryWithInitialDefs());
+  auto const block = current_block_->AsBlockEntryWithInitialDefs();
+  if (list == nullptr) return false;
+  for (intptr_t i = 2; i < list->Length(); i++) {
+    const auto def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+    const auto def = ParseDefinition(def_sexp);
+    if (def == nullptr) return false;
+    flow_graph_->AddToInitialDefinitions(block, def);
+  }
+  return true;
+}
+
+BlockEntryInstr* FlowGraphDeserializer::ParseBlockHeader(SExpList* list,
+                                                         intptr_t block_id,
+                                                         SExpSymbol* tag) {
+  ASSERT(flow_graph_ != nullptr);
+  // We should only parse block headers once.
+  ASSERT(block_map_.LookupValue(block_id) == nullptr);
+  if (list == nullptr) return nullptr;
+
+#if defined(DEBUG)
+  intptr_t parsed_block_id;
+  auto const id_sexp = CheckSymbol(Retrieve(list, 1));
+  if (!ParseBlockId(id_sexp, &parsed_block_id)) return nullptr;
+  ASSERT(block_id == parsed_block_id);
+#endif
+
+  auto const kind = FlowGraphSerializer::BlockEntryTagToKind(tag);
+
+  intptr_t deopt_id = DeoptId::kNone;
+  if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
+    deopt_id = deopt_int->value();
+  }
+  intptr_t try_index = kInvalidTryIndex;
+  if (auto const try_int = CheckInteger(list->ExtraLookupValue("try_index"))) {
+    try_index = try_int->value();
+  }
+
+  BlockEntryInstr* block = nullptr;
+  EntryInfo common_info = {block_id, try_index, deopt_id};
+  switch (kind) {
+    case FlowGraphSerializer::kTarget:
+      block = DeserializeTargetEntry(list, common_info);
+      break;
+    case FlowGraphSerializer::kNormal:
+      block = DeserializeFunctionEntry(list, common_info);
+      if (block != nullptr) {
+        auto const graph = flow_graph_->graph_entry();
+        graph->set_normal_entry(block->AsFunctionEntry());
+      }
+      break;
+    case FlowGraphSerializer::kUnchecked: {
+      block = DeserializeFunctionEntry(list, common_info);
+      if (block != nullptr) {
+        auto const graph = flow_graph_->graph_entry();
+        graph->set_unchecked_entry(block->AsFunctionEntry());
+      }
+      break;
+    }
+    case FlowGraphSerializer::kJoin:
+      block = DeserializeJoinEntry(list, common_info);
+      break;
+    case FlowGraphSerializer::kInvalid:
+      StoreError(tag, "invalid block entry tag");
+      return nullptr;
+    default:
+      StoreError(tag, "unhandled block type");
+      return nullptr;
+  }
+  if (block == nullptr) return nullptr;
+
+  block_map_.Insert(block_id, block);
+  return block;
+}
+
+bool FlowGraphDeserializer::ParsePhis(SExpList* list) {
+  ASSERT(current_block_ != nullptr && current_block_->IsJoinEntry());
+  auto const join = current_block_->AsJoinEntry();
+  const intptr_t start_pos = 2;
+  auto const end_pos = SkipPhis(list);
+  if (end_pos < start_pos) return false;
+
+  for (intptr_t i = start_pos; i < end_pos; i++) {
+    auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+    auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
+    // SkipPhis should already have checked which instructions, if any,
+    // are Phi definitions.
+    ASSERT(phi_sexp != nullptr);
+
+    // This is a generalization of FlowGraph::AddPhi where we let ParseValue
+    // create the values (as they may contain type information).
+    auto const phi = new (zone()) PhiInstr(join, phi_sexp->Length() - 1);
+    phi->mark_alive();
+    for (intptr_t i = 0, n = phi_sexp->Length() - 1; i < n; i++) {
+      auto const val = ParseValue(Retrieve(phi_sexp, i + 1));
+      if (val == nullptr) return false;
+      phi->SetInputAt(i, val);
+      val->definition()->AddInputUse(val);
+    }
+    join->InsertPhi(phi);
+
+    if (!ParseDefinitionWithParsedBody(def_sexp, phi)) return false;
+  }
+
+  return true;
+}
+
+intptr_t FlowGraphDeserializer::SkipPhis(SExpList* list) {
+  // All blocks are S-exps of the form (Block B# inst...), so skip the first
+  // two entries and then skip any Phi definitions.
+  for (intptr_t i = 2, n = list->Length(); i < n; i++) {
+    auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+    if (def_sexp == nullptr) return i;
+    auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
+    if (phi_sexp == nullptr) return i;
+  }
+
+  StoreError(list, "block is empty or contains only Phi definitions");
+  return -1;
+}
+
+bool FlowGraphDeserializer::ParseBlockContents(SExpList* list,
+                                               BlockWorklist* worklist) {
+  ASSERT(current_block_ != nullptr);
+  auto const curr_stack =
+      pushed_stack_map_.LookupValue(current_block_->block_id());
+  ASSERT(curr_stack != nullptr);
+
+  // Parse any Phi definitions now before parsing the block environment.
+  if (current_block_->IsJoinEntry()) {
+    if (!ParsePhis(list)) return false;
+  }
+
+  // For blocks with initial definitions or phi definitions, this needs to be
+  // done after those are parsed. In addition, block environments can also use
+  // definitions from dominating blocks, so we need the contents of dominating
+  // blocks to first be parsed.
+  //
+  // However, we must parse the environment before parsing any instructions
+  // in the body of the block to ensure we don't mistakenly allow local
+  // definitions to appear in the environment.
+  if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
+    auto const env = ParseEnvironment(env_sexp);
+    if (env == nullptr) return false;
+    env->DeepCopyTo(zone(), current_block_);
+  }
+
+  auto const pos = SkipPhis(list);
+  if (pos < 2) return false;
+  Instruction* last_inst = current_block_;
+  for (intptr_t i = pos, n = list->Length(); i < n; i++) {
+    auto const entry = CheckTaggedList(Retrieve(list, i));
+    if (entry == nullptr) return false;
+    Instruction* inst = nullptr;
+    if (strcmp(entry->At(0)->AsSymbol()->value(), "def") == 0) {
+      inst = ParseDefinition(entry);
+    } else {
+      inst = ParseInstruction(entry);
+    }
+    if (inst == nullptr) return false;
+    last_inst = last_inst->AppendInstruction(inst);
+  }
+
+  ASSERT(last_inst != nullptr && last_inst != current_block_);
+  if (last_inst->SuccessorCount() > 0) {
+    for (intptr_t i = last_inst->SuccessorCount() - 1; i >= 0; i--) {
+      auto const succ_block = last_inst->SuccessorAt(i);
+      // Check and make sure the stack we have is consistent with stacks
+      // from other predecessors.
+      if (!AreStacksConsistent(list, curr_stack, succ_block)) return false;
+      succ_block->AddPredecessor(current_block_);
+      worklist->Add(succ_block->block_id());
+    }
+  }
+
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseDefinitionWithParsedBody(SExpList* list,
+                                                          Definition* def) {
+  intptr_t index;
+  auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+  if (name_sexp == nullptr) return false;
+
+  if (ParseSSATemp(name_sexp, &index)) {
+    if (definition_map_.HasKey(index)) {
+      StoreError(list, "multiple definitions for the same SSA index");
+      return false;
+    }
+    def->set_ssa_temp_index(index);
+    if (index > max_ssa_index_) max_ssa_index_ = index;
+  } else {
+    // TODO(sstrickl): Add temp support for non-SSA computed graphs.
+    StoreError(list, "unhandled name for definition");
+    return false;
+  }
+
+  if (auto const type_sexp =
+          CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
+    CompileType* typ = ParseCompileType(type_sexp);
+    if (typ == nullptr) return false;
+    def->UpdateType(*typ);
+  }
+
+  definition_map_.Insert(index, def);
+  FixPendingValues(index, def);
+  return true;
+}
+
+Definition* FlowGraphDeserializer::ParseDefinition(SExpList* list) {
+  auto const inst_sexp = CheckTaggedList(Retrieve(list, 2));
+  Instruction* const inst = ParseInstruction(inst_sexp);
+  if (inst == nullptr) return nullptr;
+  if (auto const def = inst->AsDefinition()) {
+    if (!ParseDefinitionWithParsedBody(list, def)) return nullptr;
+    return def;
+  } else {
+    StoreError(list, "instruction cannot be body of definition");
+    return nullptr;
+  }
+}
+
+Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) {
+  if (list == nullptr) return nullptr;
+  auto const tag = list->At(0)->AsSymbol();
+
+  intptr_t deopt_id = DeoptId::kNone;
+  if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
+    deopt_id = deopt_int->value();
+  }
+  InstrInfo common_info = {deopt_id, TokenPosition::kNoSource};
+
+  // Parse the environment before handling the instruction, as we may have
+  // references to PushArguments and parsing the instruction may pop
+  // PushArguments off the stack.
+  Environment* env = nullptr;
+  if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
+    env = ParseEnvironment(env_sexp);
+    if (env == nullptr) return nullptr;
+  }
+
+  Instruction* inst = nullptr;
+
+#define HANDLE_CASE(name)                                                      \
+  case kHandled##name:                                                         \
+    inst = Deserialize##name(list, common_info);                               \
+    break;
+  switch (HandledInstructionForTag(tag)) {
+    FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
+    case kHandledInvalid:
+      StoreError(tag, "unhandled instruction");
+      return nullptr;
+  }
+#undef HANDLE_CASE
+
+  if (inst == nullptr) return nullptr;
+  if (env != nullptr) env->DeepCopyTo(zone(), inst);
+  return inst;
+}
+
+FunctionEntryInstr* FlowGraphDeserializer::DeserializeFunctionEntry(
+    SExpList* sexp,
+    const EntryInfo& info) {
+  ASSERT(flow_graph_ != nullptr);
+  auto const graph = flow_graph_->graph_entry();
+  auto const block = new (zone())
+      FunctionEntryInstr(graph, info.block_id, info.try_index, info.deopt_id);
+  current_block_ = block;
+  if (!ParseInitialDefinitions(sexp)) return nullptr;
+  return block;
+}
+
+GraphEntryInstr* FlowGraphDeserializer::DeserializeGraphEntry(
+    SExpList* sexp,
+    const EntryInfo& info) {
+  auto const name_sexp = CheckSymbol(Retrieve(sexp, 1));
+  // TODO(sstrickl): If the FlowGraphDeserializer was constructed with a
+  // non-null ParsedFunction, we should check that the name matches here.
+  // If not, then we should create an appropriate ParsedFunction here.
+  if (name_sexp == nullptr) return nullptr;
+
+  intptr_t osr_id = Compiler::kNoOSRDeoptId;
+  if (auto const osr_id_sexp = CheckInteger(sexp->ExtraLookupValue("osr_id"))) {
+    osr_id = osr_id_sexp->value();
+  }
+
+  ASSERT(parsed_function_ != nullptr);
+  return new (zone()) GraphEntryInstr(*parsed_function_, osr_id, info.deopt_id);
+}
+
+JoinEntryInstr* FlowGraphDeserializer::DeserializeJoinEntry(
+    SExpList* sexp,
+    const EntryInfo& info) {
+  return new (zone())
+      JoinEntryInstr(info.block_id, info.try_index, info.deopt_id);
+}
+
+TargetEntryInstr* FlowGraphDeserializer::DeserializeTargetEntry(
+    SExpList* sexp,
+    const EntryInfo& info) {
+  return new (zone())
+      TargetEntryInstr(info.block_id, info.try_index, info.deopt_id);
+}
+
+AllocateObjectInstr* FlowGraphDeserializer::DeserializeAllocateObject(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto& cls = Class::ZoneHandle(zone());
+  auto const cls_sexp = CheckTaggedList(Retrieve(sexp, 1), "Class");
+  if (!ParseDartValue(cls_sexp, &cls)) return nullptr;
+
+  intptr_t args_len = 0;
+  if (auto const len_sexp = CheckInteger(sexp->ExtraLookupValue("args_len"))) {
+    args_len = len_sexp->value();
+  }
+  auto const arguments = FetchPushedArguments(sexp, args_len);
+  if (arguments == nullptr) return nullptr;
+
+  auto const inst =
+      new (zone()) AllocateObjectInstr(info.token_pos, cls, arguments);
+
+  if (auto const closure_sexp = CheckTaggedList(
+          sexp->ExtraLookupValue("closure_function"), "Function")) {
+    auto& closure_function = Function::Handle(zone());
+    if (!ParseDartValue(closure_sexp, &closure_function)) return nullptr;
+    inst->set_closure_function(closure_function);
+  }
+
+  return inst;
+}
+
+BranchInstr* FlowGraphDeserializer::DeserializeBranch(SExpList* sexp,
+                                                      const InstrInfo& info) {
+  auto const comp_sexp = CheckTaggedList(Retrieve(sexp, 1));
+  auto const comp_inst = ParseInstruction(comp_sexp);
+  if (comp_inst == nullptr) return nullptr;
+  if (!comp_inst->IsComparison()) {
+    StoreError(sexp->At(1), "expected comparison instruction");
+    return nullptr;
+  }
+  auto const comparison = comp_inst->AsComparison();
+
+  auto const true_block = FetchBlock(CheckSymbol(Retrieve(sexp, 2)));
+  if (true_block == nullptr) return nullptr;
+  if (!true_block->IsTargetEntry()) {
+    StoreError(sexp->At(2), "true successor is not a target block");
+    return nullptr;
+  }
+
+  auto const false_block = FetchBlock(CheckSymbol(Retrieve(sexp, 3)));
+  if (false_block == nullptr) return nullptr;
+  if (!false_block->IsTargetEntry()) {
+    StoreError(sexp->At(3), "false successor is not a target block");
+    return nullptr;
+  }
+
+  auto const branch = new (zone()) BranchInstr(comparison, info.deopt_id);
+  *branch->true_successor_address() = true_block->AsTargetEntry();
+  *branch->false_successor_address() = false_block->AsTargetEntry();
+  return branch;
+}
+
+CheckNullInstr* FlowGraphDeserializer::DeserializeCheckNull(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto const val = ParseValue(Retrieve(sexp, 1));
+  if (val == nullptr) return nullptr;
+
+  auto& func_name = String::ZoneHandle(zone());
+  if (auto const name_sexp =
+          CheckString(sexp->ExtraLookupValue("function_name"))) {
+    func_name = String::New(name_sexp->value(), Heap::kOld);
+  }
+
+  return new (zone())
+      CheckNullInstr(val, func_name, info.deopt_id, info.token_pos);
+}
+
+CheckStackOverflowInstr* FlowGraphDeserializer::DeserializeCheckStackOverflow(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  intptr_t stack_depth = 0;
+  if (auto const stack_sexp =
+          CheckInteger(sexp->ExtraLookupValue("stack_depth"))) {
+    stack_depth = stack_sexp->value();
+  }
+
+  intptr_t loop_depth = 0;
+  if (auto const loop_sexp =
+          CheckInteger(sexp->ExtraLookupValue("loop_depth"))) {
+    loop_depth = loop_sexp->value();
+  }
+
+  auto kind = CheckStackOverflowInstr::kOsrAndPreemption;
+  if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
+    ASSERT(strcmp(kind_sexp->value(), "OsrOnly") == 0);
+    kind = CheckStackOverflowInstr::kOsrOnly;
+  }
+
+  return new (zone()) CheckStackOverflowInstr(info.token_pos, stack_depth,
+                                              loop_depth, info.deopt_id, kind);
+}
+
+ConstantInstr* FlowGraphDeserializer::DeserializeConstant(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  Object& obj = Object::ZoneHandle(zone());
+  if (!ParseDartValue(Retrieve(sexp, 1), &obj)) return nullptr;
+  return new (zone()) ConstantInstr(obj, info.token_pos);
+}
+
+DebugStepCheckInstr* FlowGraphDeserializer::DeserializeDebugStepCheck(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto kind = RawPcDescriptors::kAnyKind;
+  if (auto const kind_sexp = CheckSymbol(Retrieve(sexp, "stub_kind"))) {
+    if (!RawPcDescriptors::KindFromCString(kind_sexp->value(), &kind)) {
+      StoreError(kind_sexp, "not a valid RawPcDescriptors::Kind name");
+      return nullptr;
+    }
+  }
+  return new (zone()) DebugStepCheckInstr(info.token_pos, kind, info.deopt_id);
+}
+
+GotoInstr* FlowGraphDeserializer::DeserializeGoto(SExpList* sexp,
+                                                  const InstrInfo& info) {
+  auto const block = FetchBlock(CheckSymbol(Retrieve(sexp, 1)));
+  if (block == nullptr) return nullptr;
+  if (!block->IsJoinEntry()) {
+    StoreError(sexp->At(1), "target of goto must be join entry");
+    return nullptr;
+  }
+  return new (zone()) GotoInstr(block->AsJoinEntry(), info.deopt_id);
+}
+
+LoadFieldInstr* FlowGraphDeserializer::DeserializeLoadField(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto const instance = ParseValue(Retrieve(sexp, 1));
+  if (instance == nullptr) return nullptr;
+
+  const Slot* slot;
+  if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2)), &slot)) return nullptr;
+
+  return new (zone()) LoadFieldInstr(instance, *slot, info.token_pos);
+}
+
+ParameterInstr* FlowGraphDeserializer::DeserializeParameter(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  ASSERT(current_block_ != nullptr);
+  if (auto const index_sexp = CheckInteger(Retrieve(sexp, 1))) {
+    return new (zone()) ParameterInstr(index_sexp->value(), current_block_);
+  }
+  return nullptr;
+}
+
+PushArgumentInstr* FlowGraphDeserializer::DeserializePushArgument(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto const val = ParseValue(Retrieve(sexp, 1));
+  if (val == nullptr) return nullptr;
+  auto const push = new (zone()) PushArgumentInstr(val);
+  auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+  ASSERT(stack != nullptr);
+  stack->Add(push);
+  return push;
+}
+
+ReturnInstr* FlowGraphDeserializer::DeserializeReturn(SExpList* list,
+                                                      const InstrInfo& info) {
+  Value* val = ParseValue(Retrieve(list, 1));
+  if (val == nullptr) return nullptr;
+  return new (zone()) ReturnInstr(info.token_pos, val, info.deopt_id);
+}
+
+SpecialParameterInstr* FlowGraphDeserializer::DeserializeSpecialParameter(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  ASSERT(current_block_ != nullptr);
+  auto const kind_sexp = CheckSymbol(Retrieve(sexp, 1));
+  if (kind_sexp == nullptr) return nullptr;
+  SpecialParameterInstr::SpecialParameterKind kind;
+  if (!SpecialParameterInstr::KindFromCString(kind_sexp->value(), &kind)) {
+    StoreError(kind_sexp, "unknown special parameter kind");
+    return nullptr;
+  }
+  return new (zone())
+      SpecialParameterInstr(kind, info.deopt_id, current_block_);
+}
+
+StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto& function = Function::ZoneHandle(zone());
+  auto const function_sexp = CheckTaggedList(Retrieve(sexp, 1), "Function");
+  if (!ParseDartValue(function_sexp, &function)) return nullptr;
+
+  intptr_t type_args_len = 0;
+  if (auto const type_args_len_sexp =
+          CheckInteger(sexp->ExtraLookupValue("type_args_len"))) {
+    type_args_len = type_args_len_sexp->value();
+  }
+
+  Array& argument_names = Array::ZoneHandle(zone());
+  if (auto const arg_names_sexp =
+          CheckList(sexp->ExtraLookupValue("arg_names"))) {
+    argument_names = Array::New(arg_names_sexp->Length(), Heap::kOld);
+    for (intptr_t i = 0, n = arg_names_sexp->Length(); i < n; i++) {
+      auto name_sexp = CheckString(Retrieve(arg_names_sexp, i));
+      if (name_sexp == nullptr) return nullptr;
+      tmp_string_ = String::New(name_sexp->value(), Heap::kOld);
+      argument_names.SetAt(i, tmp_string_);
+    }
+  }
+
+  intptr_t args_len = 0;
+  if (auto const args_len_sexp =
+          CheckInteger(sexp->ExtraLookupValue("args_len"))) {
+    args_len = args_len_sexp->value();
+  }
+
+  // Type arguments are wrapped in a TypeArguments array, so no matter how
+  // many there are, they are contained in a single pushed argument.
+  auto const all_args_len = (type_args_len > 0 ? 1 : 0) + args_len;
+  auto const arguments = FetchPushedArguments(sexp, all_args_len);
+  if (arguments == nullptr) return nullptr;
+
+  intptr_t call_count = 0;
+  if (auto const call_count_sexp =
+          CheckInteger(sexp->ExtraLookupValue("call_count"))) {
+    call_count = call_count_sexp->value();
+  }
+
+  auto rebind_rule = ICData::kInstance;
+  if (auto const rebind_sexp =
+          CheckSymbol(sexp->ExtraLookupValue("rebind_rule"))) {
+    if (!ICData::RebindRuleFromCString(rebind_sexp->value(), &rebind_rule)) {
+      StoreError(rebind_sexp, "unknown rebind rule value");
+      return nullptr;
+    }
+  }
+
+  return new (zone())
+      StaticCallInstr(info.token_pos, function, type_args_len, argument_names,
+                      arguments, info.deopt_id, call_count, rebind_rule);
+}
+
+StoreInstanceFieldInstr* FlowGraphDeserializer::DeserializeStoreInstanceField(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto const instance = ParseValue(Retrieve(sexp, 1));
+  if (instance == nullptr) return nullptr;
+
+  const Slot* slot = nullptr;
+  if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2), "Slot"), &slot)) {
+    return nullptr;
+  }
+
+  auto const value = ParseValue(Retrieve(sexp, 3));
+  if (value == nullptr) return nullptr;
+
+  auto barrier_type = kNoStoreBarrier;
+  if (auto const bar_sexp = CheckBool(sexp->ExtraLookupValue("emit_barrier"))) {
+    if (bar_sexp->value()) barrier_type = kEmitStoreBarrier;
+  }
+
+  auto kind = StoreInstanceFieldInstr::Kind::kOther;
+  if (auto const init_sexp = CheckBool(sexp->ExtraLookupValue("is_init"))) {
+    if (init_sexp->value()) kind = StoreInstanceFieldInstr::Kind::kInitializing;
+  }
+
+  return new (zone()) StoreInstanceFieldInstr(
+      *slot, instance, value, barrier_type, info.token_pos, kind);
+}
+
+StrictCompareInstr* FlowGraphDeserializer::DeserializeStrictCompare(
+    SExpList* sexp,
+    const InstrInfo& info) {
+  auto const token_sexp = CheckSymbol(Retrieve(sexp, 1));
+  if (token_sexp == nullptr) return nullptr;
+  Token::Kind kind;
+  if (!Token::FromStr(token_sexp->value(), &kind)) return nullptr;
+
+  auto const left = ParseValue(Retrieve(sexp, 2));
+  if (left == nullptr) return nullptr;
+
+  auto const right = ParseValue(Retrieve(sexp, 3));
+  if (right == nullptr) return nullptr;
+
+  bool needs_check = false;
+  if (auto const check_sexp = CheckBool(Retrieve(sexp, "needs_check"))) {
+    needs_check = check_sexp->value();
+  }
+
+  return new (zone()) StrictCompareInstr(info.token_pos, kind, left, right,
+                                         needs_check, info.deopt_id);
+}
+
+Value* FlowGraphDeserializer::ParseValue(SExpression* sexp,
+                                         bool allow_pending) {
+  auto name = sexp->AsSymbol();
+  CompileType* type = nullptr;
+  if (name == nullptr) {
+    auto const list = CheckTaggedList(sexp, "value");
+    name = CheckSymbol(Retrieve(list, 1));
+    if (name == nullptr) return nullptr;
+    if (auto const type_sexp =
+            CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
+      type = ParseCompileType(type_sexp);
+      if (type == nullptr) return nullptr;
+    }
+  }
+  intptr_t index;
+  if (!ParseUse(name, &index)) return nullptr;
+  auto const def = definition_map_.LookupValue(index);
+  Value* val;
+  if (def == nullptr) {
+    if (!allow_pending) {
+      StoreError(sexp, "found use prior to definition");
+      return nullptr;
+    }
+    val = AddNewPendingValue(index);
+  } else {
+    val = new (zone()) Value(def);
+  }
+  if (type != nullptr) val->SetReachingType(type);
+  return val;
+}
+
+CompileType* FlowGraphDeserializer::ParseCompileType(SExpList* sexp) {
+  // TODO(sstrickl): Currently we only print out nullable if it's false
+  // (or during verbose printing). Switch this when NNBD is the standard.
+  bool nullable = CompileType::kNullable;
+  if (auto const nullable_sexp =
+          CheckBool(sexp->ExtraLookupValue("nullable"))) {
+    nullable = nullable_sexp->value() ? CompileType::kNullable
+                                      : CompileType::kNonNullable;
+  }
+
+  // A cid as the second element means that the type is based off a concrete
+  // class.
+  intptr_t cid = kDynamicCid;
+  if (sexp->Length() > 1) {
+    if (auto const cid_sexp = CheckInteger(sexp->At(1))) {
+      // TODO(sstrickl): Check that the cid is a valid cid.
+      cid = cid_sexp->value();
+    } else {
+      return nullptr;
+    }
+  }
+
+  AbstractType* type = nullptr;
+  if (auto const type_sexp = CheckTaggedList(sexp->ExtraLookupValue("type"))) {
+    auto& type_handle = AbstractType::ZoneHandle(zone());
+    if (!ParseDartValue(type_sexp, &type_handle)) return nullptr;
+    type = &type_handle;
+  }
+  return new (zone()) CompileType(nullable, cid, type);
+}
+
+Environment* FlowGraphDeserializer::ParseEnvironment(SExpList* list) {
+  if (list == nullptr) return nullptr;
+  intptr_t fixed_param_count = 0;
+  if (auto const fpc_sexp =
+          CheckInteger(list->ExtraLookupValue("fixed_param_count"))) {
+    fixed_param_count = fpc_sexp->value();
+  }
+  Environment* outer_env = nullptr;
+  if (auto const outer_sexp = CheckList(list->ExtraLookupValue("outer"))) {
+    outer_env = ParseEnvironment(outer_sexp);
+    if (outer_env == nullptr) return nullptr;
+    if (auto const deopt_sexp =
+            CheckInteger(outer_sexp->ExtraLookupValue("deopt_id"))) {
+      outer_env->deopt_id_ = deopt_sexp->value();
+    }
+  }
+
+  auto const env = new (zone()) Environment(list->Length(), fixed_param_count,
+                                            *parsed_function_, outer_env);
+
+  auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+  ASSERT(stack != nullptr);
+  for (intptr_t i = 0; i < list->Length(); i++) {
+    auto const elem_sexp = Retrieve(list, i);
+    if (elem_sexp == nullptr) return nullptr;
+    auto val = ParseValue(elem_sexp, /*allow_pending=*/false);
+    if (val == nullptr) {
+      intptr_t index;
+      if (!ParseSymbolAsPrefixedInt(CheckSymbol(elem_sexp), 'a', &index)) {
+        StoreError(elem_sexp, "expected value or reference to pushed argument");
+        return nullptr;
+      }
+      if (index >= stack->length()) {
+        StoreError(elem_sexp, "out of range index for pushed argument");
+        return nullptr;
+      }
+      val = new (zone()) Value(stack->At(index));
+    }
+    env->PushValue(val);
+  }
+
+  return env;
+}
+
+bool FlowGraphDeserializer::ParseDartValue(SExpression* sexp, Object* out) {
+  ASSERT(out != nullptr);
+  if (sexp == nullptr) return false;
+  *out = Object::null();
+
+  if (auto const sym = sexp->AsSymbol()) {
+    // We'll use the null value in *out as a marker later, so go ahead and exit
+    // early if we parse one.
+    if (strcmp(sym->value(), "null") == 0) return true;
+
+    // The only other symbols that should appear in Dart value position are
+    // names of constant definitions.
+    auto const val = ParseValue(sym, /*allow_pending=*/false);
+    if (val == nullptr) return false;
+    if (!val->BindsToConstant()) {
+      StoreError(sym, "not a reference to a constant definition");
+      return false;
+    }
+    *out = val->BoundConstant().raw();
+    // Values used in constant definitions have already been canonicalized,
+    // so just exit.
+    return true;
+  }
+
+  // Other instance values may need to be canonicalized, so do that before
+  // returning.
+  if (auto const list = CheckTaggedList(sexp)) {
+    auto const tag = list->At(0)->AsSymbol();
+    if (strcmp(tag->value(), "Class") == 0) {
+      auto const cid_sexp = CheckInteger(Retrieve(list, 1));
+      if (cid_sexp == nullptr) return false;
+      ClassTable* table = thread()->isolate()->class_table();
+      if (!table->HasValidClassAt(cid_sexp->value())) {
+        StoreError(cid_sexp, "no valid class found for cid");
+        return false;
+      }
+      *out = table->At(cid_sexp->value());
+    } else if (strcmp(tag->value(), "Type") == 0) {
+      if (const auto cls_sexp = CheckTaggedList(Retrieve(list, 1), "Class")) {
+        auto& cls = Class::ZoneHandle(zone());
+        if (!ParseDartValue(cls_sexp, &cls)) return false;
+        auto& type_args = TypeArguments::ZoneHandle(zone());
+        if (const auto ta_sexp = CheckTaggedList(
+                list->ExtraLookupValue("type_args"), "TypeArguments")) {
+          if (!ParseDartValue(ta_sexp, &type_args)) return false;
+        }
+        *out = Type::New(cls, type_args, TokenPosition::kNoSource, Heap::kOld);
+        // Need to set this for canonicalization. We ensure in the serializer
+        // that only finalized types are successfully serialized.
+        Type::Cast(*out).SetIsFinalized();
+      }
+      // TODO(sstrickl): Handle types not derived from classes.
+    } else if (strcmp(tag->value(), "TypeArguments") == 0) {
+      *out = TypeArguments::New(list->Length() - 1, Heap::kOld);
+      auto& type_args = TypeArguments::Cast(*out);
+      for (intptr_t i = 1, n = list->Length(); i < n; i++) {
+        if (!ParseDartValue(Retrieve(list, i), &value_type_)) return false;
+        type_args.SetTypeAt(i - 1, value_type_);
+      }
+    } else if (strcmp(tag->value(), "Field") == 0) {
+      auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+      if (!ParseCanonicalName(name_sexp, out)) return false;
+    } else if (strcmp(tag->value(), "Function") == 0) {
+      auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+      if (!ParseCanonicalName(name_sexp, out)) return false;
+      // Check the kind expected by the S-expression if one was specified.
+      if (auto const kind_sexp = CheckSymbol(list->ExtraLookupValue("kind"))) {
+        RawFunction::Kind kind;
+        if (!RawFunction::KindFromCString(kind_sexp->value(), &kind)) {
+          StoreError(kind_sexp, "unexpected function kind");
+          return false;
+        }
+        auto& function = Function::Cast(*out);
+        if (function.kind() != kind) {
+          auto const kind_str = RawFunction::KindToCString(function.kind());
+          StoreError(list, "retrieved function has kind %s", kind_str);
+          return false;
+        }
+      }
+    } else if (strcmp(tag->value(), "TypeParameter") == 0) {
+      ASSERT(parsed_function_ != nullptr);
+      auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+      if (name_sexp == nullptr) return false;
+      const auto& func = parsed_function_->function();
+      tmp_string_ = String::New(name_sexp->value());
+      *out = func.LookupTypeParameter(tmp_string_, nullptr);
+      if (out->IsNull()) {
+        // Check the owning class for the function as well.
+        value_class_ = func.Owner();
+        *out = value_class_.LookupTypeParameter(tmp_string_);
+      }
+      // We'll want a more specific error message than the generic unhandled
+      // Dart value one if this failed.
+      if (out->IsNull()) {
+        StoreError(name_sexp, "no type parameter found for name");
+        return false;
+      }
+    } else if (strcmp(tag->value(), "ImmutableList") == 0) {
+      // Since arrays can contain arrays, we must allocate a new handle here.
+      auto& arr =
+          Array::Handle(zone(), Array::New(list->Length() - 1, Heap::kOld));
+      for (intptr_t i = 1; i < list->Length(); i++) {
+        if (!ParseDartValue(Retrieve(list, i), &value_object_)) return false;
+        arr.SetAt(i - 1, value_object_);
+      }
+      if (auto type_args_sexp = CheckTaggedList(
+              list->ExtraLookupValue("type_args"), "TypeArguments")) {
+        if (!ParseDartValue(type_args_sexp, &value_type_args_)) return false;
+        arr.SetTypeArguments(value_type_args_);
+      }
+      arr.MakeImmutable();
+      *out = arr.raw();
+    } else if (strcmp(tag->value(), "Instance") == 0) {
+      if (!ParseInstance(list, reinterpret_cast<Instance*>(out))) return false;
+    } else if (strcmp(tag->value(), "Closure") == 0) {
+      auto& function = Function::ZoneHandle(zone());
+      if (!ParseDartValue(Retrieve(list, 1), &function)) return false;
+
+      auto& context = Context::ZoneHandle(zone());
+      if (list->ExtraLookupValue("context") != nullptr) {
+        StoreError(list, "closures with contexts currently unhandled");
+        return false;
+      }
+
+      auto& inst_type_args = TypeArguments::ZoneHandle(zone());
+      if (auto const type_args_sexp = CheckTaggedList(
+              Retrieve(list, "inst_type_args"), "TypeArguments")) {
+        if (!ParseDartValue(type_args_sexp, &inst_type_args)) return false;
+      }
+
+      auto& func_type_args = TypeArguments::ZoneHandle(zone());
+      if (auto const type_args_sexp = CheckTaggedList(
+              Retrieve(list, "func_type_args"), "TypeArguments")) {
+        if (!ParseDartValue(type_args_sexp, &func_type_args)) return false;
+      }
+
+      auto& delayed_type_args = TypeArguments::ZoneHandle(zone());
+      if (auto const type_args_sexp = CheckTaggedList(
+              Retrieve(list, "delayed_type_args"), "TypeArguments")) {
+        if (!ParseDartValue(type_args_sexp, &delayed_type_args)) return false;
+      }
+
+      *out = Closure::New(inst_type_args, func_type_args, delayed_type_args,
+                          function, context, Heap::kOld);
+    }
+  } else if (auto const b = sexp->AsBool()) {
+    *out = Bool::Get(b->value()).raw();
+  } else if (auto const str = sexp->AsString()) {
+    *out = String::New(str->value(), Heap::kOld);
+  } else if (auto const i = sexp->AsInteger()) {
+    *out = Integer::New(i->value(), Heap::kOld);
+  } else if (auto const d = sexp->AsDouble()) {
+    *out = Double::New(d->value(), Heap::kOld);
+  }
+
+  // If we're here and still haven't gotten a non-null value, then something
+  // went wrong. (Likely an unrecognized value.)
+  if (out->IsNull()) {
+    StoreError(sexp, "unhandled Dart value");
+    return false;
+  }
+
+  if (out->IsInstance()) {
+    const char* error_str = nullptr;
+    // CheckAndCanonicalize uses the current zone for the passed in thread,
+    // not an explicitly provided zone. This means we cannot be run in a context
+    // where [thread()->zone()] does not match [zone()] (e.g., due to StackZone)
+    // until this is addressed.
+    *out = Instance::Cast(*out).CheckAndCanonicalize(thread(), &error_str);
+    if (out->IsNull()) {
+      if (error_str != nullptr) {
+        StoreError(sexp, "error during canonicalization: %s", error_str);
+      } else {
+        StoreError(sexp, "unexpected error during canonicalization");
+      }
+      return false;
+    }
+  }
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseInstance(SExpList* list, Instance* out) {
+  auto const cid_sexp = CheckInteger(Retrieve(list, 1));
+  if (cid_sexp == nullptr) return false;
+
+  auto const table = thread()->isolate()->class_table();
+  if (!table->HasValidClassAt(cid_sexp->value())) {
+    StoreError(cid_sexp, "cid is not valid");
+    return false;
+  }
+
+  instance_class_ = table->At(cid_sexp->value());
+  *out = Instance::New(instance_class_, Heap::kOld);
+
+  if (list->Length() > 2) {
+    auto const fields_sexp = CheckTaggedList(Retrieve(list, 2), "Fields");
+    if (fields_sexp == nullptr) return false;
+    auto it = fields_sexp->ExtraIterator();
+    while (auto kv = it.Next()) {
+      tmp_string_ = String::New(kv->key);
+      instance_field_ = instance_class_.LookupFieldAllowPrivate(
+          tmp_string_, /*instance_only=*/true);
+      if (instance_field_.IsNull()) {
+        StoreError(list, "cannot find field %s", kv->key);
+        return false;
+      }
+
+      if (auto const inst = CheckTaggedList(kv->value, "Instance")) {
+        // Unsure if this will be necessary, so for now not doing fresh
+        // Instance/Class handle allocations unless it is.
+        StoreError(inst, "nested instances not handled yet");
+        return false;
+      }
+      if (!ParseDartValue(kv->value, &instance_object_)) return false;
+      out->SetField(instance_field_, instance_object_);
+    }
+  }
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseCanonicalName(SExpSymbol* sym, Object* obj) {
+  if (sym == nullptr) return false;
+  auto const name = sym->value();
+  // TODO(sstrickl): No library URL, handle this better.
+  if (*name == ':') {
+    StoreError(sym, "expected non-empty library");
+    return false;
+  }
+  const char* lib_end = nullptr;
+  if (auto const first = strchr(name, ':')) {
+    lib_end = strchr(first + 1, ':');
+    if (lib_end == nullptr) lib_end = strchr(first + 1, '\0');
+  } else {
+    StoreError(sym, "malformed library");
+    return false;
+  }
+  tmp_string_ =
+      String::FromUTF8(reinterpret_cast<const uint8_t*>(name), lib_end - name);
+  name_library_ = Library::LookupLibrary(thread(), tmp_string_);
+  if (*lib_end == '\0') {
+    *obj = name_library_.raw();
+    return true;
+  }
+  const char* const class_start = lib_end + 1;
+  if (*class_start == '\0') {
+    StoreError(sym, "no class found after colon");
+    return false;
+  }
+  // If classes are followed by another part, it's either a function
+  // (separated by ':') or a field (separated by '.').
+  const char* class_end = strchr(class_start, ':');
+  if (class_end == nullptr) class_end = strchr(class_start, '.');
+  if (class_end == nullptr) class_end = strchr(class_start, '\0');
+  const bool empty_name = class_end == class_start;
+  name_class_ = Class::null();
+  if (empty_name) {
+    name_class_ = name_library_.toplevel_class();
+  } else {
+    tmp_string_ = String::FromUTF8(
+        reinterpret_cast<const uint8_t*>(class_start), class_end - class_start);
+    name_class_ = name_library_.LookupClassAllowPrivate(tmp_string_);
+  }
+  if (name_class_.IsNull()) {
+    StoreError(sym, "failure looking up class %s in library %s",
+               empty_name ? "at top level" : tmp_string_.ToCString(),
+               name_library_.ToCString());
+    return false;
+  }
+  if (*class_end == '\0') {
+    *obj = name_class_.raw();
+    return true;
+  }
+  if (*class_end == '.') {
+    if (class_end[1] == '\0') {
+      StoreError(sym, "no field name found after period");
+      return false;
+    }
+    const char* const field_start = class_end + 1;
+    const char* field_end = strchr(field_start, '\0');
+    tmp_string_ = String::FromUTF8(
+        reinterpret_cast<const uint8_t*>(field_start), field_end - field_start);
+    name_field_ = name_class_.LookupFieldAllowPrivate(tmp_string_);
+    if (name_field_.IsNull()) {
+      StoreError(sym, "failure looking up field %s in class %s",
+                 tmp_string_.ToCString(),
+                 empty_name ? "at top level" : name_class_.ToCString());
+      return false;
+    }
+    *obj = name_field_.raw();
+    return true;
+  }
+  if (class_end[1] == '\0') {
+    StoreError(sym, "no function name found after final colon");
+    return false;
+  }
+  const char* func_start = class_end + 1;
+  name_function_ = Function::null();
+  while (true) {
+    const char* func_end = strchr(func_start, ':');
+    intptr_t name_len = func_end - func_start;
+    bool is_forwarder = false;
+    if (func_end != nullptr && name_len == 3) {
+      // Special case for getters/setters, where they are prefixed with "get:"
+      // or "set:", as those colons should not be used as separators.
+      if (strncmp(func_start, "get", 3) == 0 ||
+          strncmp(func_start, "set", 3) == 0) {
+        func_end = strchr(func_end + 1, ':');
+      } else if (strncmp(func_start, "dyn", 3) == 0) {
+        // Dynamic invocation forwarders start with "dyn:" and we'll need to
+        // look up the base function and then retrieve the forwarder from it.
+        is_forwarder = true;
+        func_start = func_end + 1;
+        func_end = strchr(func_end + 1, ':');
+      }
+    }
+    if (func_end == nullptr) func_end = strchr(func_start, '\0');
+    name_len = func_end - func_start;
+
+    // Check for tearoff names before we overwrite the contents of tmp_string_.
+    if (!name_function_.IsNull()) {
+      ASSERT(!tmp_string_.IsNull());
+      auto const parent_name = tmp_string_.ToCString();
+      // ImplicitClosureFunctions (tearoffs) have the same name as the Function
+      // to which they are attached. We won't handle any further nesting.
+      if (name_function_.HasImplicitClosureFunction() && *func_end == '\0' &&
+          strncmp(parent_name, func_start, name_len) == 0) {
+        *obj = name_function_.ImplicitClosureFunction();
+        return true;
+      }
+      StoreError(sym, "no handling for local functions");
+      return false;
+    }
+
+    tmp_string_ = String::FromUTF8(reinterpret_cast<const uint8_t*>(func_start),
+                                   name_len);
+    name_function_ = name_class_.LookupFunctionAllowPrivate(tmp_string_);
+    if (name_function_.IsNull()) {
+      StoreError(sym, "failure looking up function %s in class %s",
+                 tmp_string_.ToCString(), name_class_.ToCString());
+      return false;
+    }
+    if (is_forwarder) {
+      // Go back four characters to start at the 'dyn:' we stripped earlier.
+      tmp_string_ = String::FromUTF8(
+          reinterpret_cast<const uint8_t*>(func_start - 4), name_len + 4);
+      name_function_ =
+          name_function_.GetDynamicInvocationForwarder(tmp_string_);
+    }
+    if (func_end[0] == '\0') break;
+    if (func_end[1] == '\0') {
+      StoreError(sym, "no function name found after final colon");
+      return false;
+    }
+    func_start = func_end + 1;
+  }
+  *obj = name_function_.raw();
+  return true;
+}
+
+// Following the lead of BaseFlowGraphBuilder::MayCloneField here.
+const Field& FlowGraphDeserializer::MayCloneField(const Field& field) {
+  if ((Compiler::IsBackgroundCompilation() ||
+       FLAG_force_clone_compiler_objects) &&
+      field.IsOriginal()) {
+    return Field::ZoneHandle(zone(), field.CloneFromOriginal());
+  }
+  ASSERT(field.IsZoneHandle());
+  return field;
+}
+
+bool FlowGraphDeserializer::ParseSlot(SExpList* list, const Slot** out) {
+  ASSERT(out != nullptr);
+  const auto offset_sexp = CheckInteger(Retrieve(list, 1));
+  if (offset_sexp == nullptr) return false;
+  const auto offset = offset_sexp->value();
+
+  const auto kind_sexp = CheckSymbol(Retrieve(list, "kind"));
+  if (kind_sexp == nullptr) return false;
+  Slot::Kind kind;
+  if (!Slot::KindFromCString(kind_sexp->value(), &kind)) {
+    StoreError(kind_sexp, "unknown Slot kind");
+    return false;
+  }
+
+  switch (kind) {
+    case Slot::Kind::kDartField: {
+      auto& field = Field::ZoneHandle(zone());
+      const auto field_sexp = CheckTaggedList(Retrieve(list, "field"), "Field");
+      if (!ParseDartValue(field_sexp, &field)) return false;
+      *out = &Slot::Get(MayCloneField(field), parsed_function_);
+      break;
+    }
+    case Slot::Kind::kTypeArguments:
+      *out = &Slot::GetTypeArgumentsSlotAt(thread(), offset);
+      break;
+    case Slot::Kind::kCapturedVariable:
+      StoreError(kind_sexp, "unhandled Slot kind");
+      return false;
+    default:
+      *out = &Slot::GetNativeSlot(kind);
+      break;
+  }
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseBlockId(SExpSymbol* sym, intptr_t* out) {
+  return ParseSymbolAsPrefixedInt(sym, 'B', out);
+}
+
+bool FlowGraphDeserializer::ParseSSATemp(SExpSymbol* sym, intptr_t* out) {
+  return ParseSymbolAsPrefixedInt(sym, 'v', out);
+}
+
+bool FlowGraphDeserializer::ParseUse(SExpSymbol* sym, intptr_t* out) {
+  // TODO(sstrickl): Handle non-SSA temp uses.
+  return ParseSSATemp(sym, out);
+}
+
+bool FlowGraphDeserializer::ParseSymbolAsPrefixedInt(SExpSymbol* sym,
+                                                     char prefix,
+                                                     intptr_t* out) {
+  ASSERT(out != nullptr);
+  if (sym == nullptr) return false;
+  auto const name = sym->value();
+  if (*name != prefix) {
+    StoreError(sym, "expected symbol starting with '%c'", prefix);
+    return false;
+  }
+  int64_t i;
+  if (!OS::StringToInt64(name + 1, &i)) {
+    StoreError(sym, "expected number following symbol prefix '%c'", prefix);
+    return false;
+  }
+  *out = i;
+  return true;
+}
+
+Value* FlowGraphDeserializer::AddNewPendingValue(intptr_t index) {
+  ASSERT(flow_graph_ != nullptr);
+  auto const val = new (zone()) Value(flow_graph_->constant_null());
+  AddPendingValue(index, val);
+  return val;
+}
+
+void FlowGraphDeserializer::AddPendingValue(intptr_t index, Value* val) {
+  ASSERT(!definition_map_.HasKey(index));
+  auto value_list = values_map_.LookupValue(index);
+  if (value_list == nullptr) {
+    value_list = new (zone()) ZoneGrowableArray<Value*>(zone(), 2);
+    values_map_.Insert(index, value_list);
+  }
+  value_list->Add(val);
+}
+
+void FlowGraphDeserializer::FixPendingValues(intptr_t index, Definition* def) {
+  if (auto value_list = values_map_.LookupValue(index)) {
+    for (intptr_t i = 0; i < value_list->length(); i++) {
+      auto const val = value_list->At(i);
+      val->BindTo(def);
+    }
+    values_map_.Remove(index);
+  }
+}
+
+PushArgumentsArray* FlowGraphDeserializer::FetchPushedArguments(SExpList* list,
+                                                                intptr_t len) {
+  auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+  ASSERT(stack != nullptr);
+  auto const stack_len = stack->length();
+  if (len > stack_len) {
+    StoreError(list, "expected %" Pd " pushed arguments, only %" Pd " on stack",
+               len, stack_len);
+    return nullptr;
+  }
+  auto const arr = new (zone()) PushArgumentsArray(zone(), len);
+  for (intptr_t i = 0; i < len; i++) {
+    arr->Add(stack->At(stack_len - len + i));
+  }
+  stack->TruncateTo(stack_len - len);
+  return arr;
+}
+
+BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) {
+  if (sym == nullptr) return nullptr;
+  intptr_t block_id;
+  if (!ParseBlockId(sym, &block_id)) return nullptr;
+  auto const entry = block_map_.LookupValue(block_id);
+  if (entry == nullptr) {
+    StoreError(sym, "reference to undefined block");
+    return nullptr;
+  }
+  return entry;
+}
+
+bool FlowGraphDeserializer::AreStacksConsistent(SExpList* list,
+                                                PushStack* curr_stack,
+                                                BlockEntryInstr* succ_block) {
+  auto const curr_stack_len = curr_stack->length();
+  for (intptr_t i = 0, n = succ_block->SuccessorCount(); i < n; i++) {
+    auto const pred_block = succ_block->PredecessorAt(i);
+    auto const pred_stack =
+        pushed_stack_map_.LookupValue(pred_block->block_id());
+    ASSERT(pred_stack != nullptr);
+    if (pred_stack->length() != curr_stack_len) {
+      StoreError(list->At(1),
+                 "current pushed stack has %" Pd
+                 " elements, "
+                 "other pushed stack for B%" Pd " has %" Pd "",
+                 curr_stack_len, pred_block->block_id(), pred_stack->length());
+      return false;
+    }
+    for (intptr_t i = 0; i < curr_stack_len; i++) {
+      // Leftover pushed arguments on the stack should come from dominating
+      // nodes, so they should be the same PushedArgumentInstr no matter the
+      // predecessor.
+      if (pred_stack->At(i) != curr_stack->At(i)) {
+        auto const pred_def = pred_stack->At(i)->value()->definition();
+        auto const curr_def = curr_stack->At(i)->value()->definition();
+        StoreError(list->At(1),
+                   "current pushed stack has v%" Pd " at position %" Pd
+                   ", "
+                   "other pushed stack for B%" Pd " has v%" Pd "",
+                   curr_def->ssa_temp_index(), i, pred_block->block_id(),
+                   pred_def->ssa_temp_index());
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+#define BASE_CHECK_DEF(name, type)                                             \
+  SExp##name* FlowGraphDeserializer::Check##name(SExpression* sexp) {          \
+    if (sexp == nullptr) return nullptr;                                       \
+    if (!sexp->Is##name()) {                                                   \
+      StoreError(sexp, "expected " #name);                                     \
+      return nullptr;                                                          \
+    }                                                                          \
+    return sexp->As##name();                                                   \
+  }
+
+FOR_EACH_S_EXPRESSION(BASE_CHECK_DEF)
+
+#undef BASE_CHECK_DEF
+
+bool FlowGraphDeserializer::IsTag(SExpression* sexp, const char* label) {
+  auto const sym = CheckSymbol(sexp);
+  if (sym == nullptr) return false;
+  if (label != nullptr && strcmp(label, sym->value()) != 0) {
+    StoreError(sym, "expected symbol %s", label);
+    return false;
+  }
+  return true;
+}
+
+SExpList* FlowGraphDeserializer::CheckTaggedList(SExpression* sexp,
+                                                 const char* label) {
+  auto const list = CheckList(sexp);
+  const intptr_t tag_pos = 0;
+  if (!IsTag(Retrieve(list, tag_pos), label)) return nullptr;
+  return list;
+}
+
+void FlowGraphDeserializer::StoreError(SExpression* sexp,
+                                       const char* format,
+                                       ...) {
+  va_list args;
+  va_start(args, format);
+  const char* const message = OS::VSCreate(zone(), format, args);
+  va_end(args);
+  error_sexp_ = sexp;
+  error_message_ = message;
+}
+
+void FlowGraphDeserializer::ReportError() const {
+  ASSERT(error_sexp_ != nullptr);
+  ASSERT(error_message_ != nullptr);
+  OS::PrintErr("Unable to deserialize flow_graph: %s\n", error_message_);
+  OS::PrintErr("Error at S-expression %s\n", error_sexp_->ToCString(zone()));
+  OS::Abort();
+}
+
+}  // namespace dart
+
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/il_deserializer.h b/runtime/vm/compiler/backend/il_deserializer.h
new file mode 100644
index 0000000..2ebb507
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_deserializer.h
@@ -0,0 +1,362 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
+#define RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
+
+#include "platform/assert.h"
+
+#include "vm/allocation.h"
+#include "vm/compiler/backend/flow_graph.h"
+#include "vm/compiler/backend/il.h"
+#include "vm/compiler/backend/sexpression.h"
+#include "vm/compiler/compiler_pass.h"
+#include "vm/object.h"
+#include "vm/parser.h"
+#include "vm/thread.h"
+#include "vm/zone.h"
+
+namespace dart {
+
+// Deserializes FlowGraphs from S-expressions.
+class FlowGraphDeserializer : ValueObject {
+ public:
+  // Adds to the given array all the instructions in the flow graph that are
+  // guaranteed not to be handled by the current implementation of the
+  // FlowGraphDeserializer. This way, we can filter out graphs that are
+  // guaranteed not to be deserializable before going through the round-trip
+  // serialization process.
+  //
+  // Note that there may be other reasons that the deserializer may fail on
+  // a given flow graph, so no new members of the array is necessary, but not
+  // sufficient, for a successful round-trip pass.
+  static void AllUnhandledInstructions(const FlowGraph* graph,
+                                       GrowableArray<Instruction*>* out);
+
+  // Takes the FlowGraph from [state] and runs it through the serializer
+  // and deserializer. If the deserializer successfully deserializes the
+  // graph, then the FlowGraph in [state] is replaced with the new one.
+  static void RoundTripSerialization(CompilerPassState* state);
+
+  FlowGraphDeserializer(Thread* thread,
+                        Zone* zone,
+                        SExpression* root,
+                        const ParsedFunction* pf = nullptr)
+      : thread_(ASSERT_NOTNULL(thread)),
+        zone_(ASSERT_NOTNULL(zone)),
+        root_sexp_(ASSERT_NOTNULL(root)),
+        parsed_function_(pf),
+        block_map_(zone_),
+        pushed_stack_map_(zone_),
+        definition_map_(zone_),
+        values_map_(zone_),
+        instance_class_(Class::Handle(zone)),
+        instance_field_(Field::Handle(zone)),
+        instance_object_(Object::Handle(zone)),
+        name_class_(Class::Handle(zone)),
+        name_field_(Field::Handle(zone)),
+        name_function_(Function::Handle(zone)),
+        name_library_(Library::Handle(zone)),
+        value_class_(Class::Handle(zone)),
+        value_object_(Object::Handle(zone)),
+        value_type_(AbstractType::Handle(zone)),
+        value_type_args_(TypeArguments::Handle(zone)),
+        tmp_string_(String::Handle(zone)) {
+    // See canonicalization comment in ParseDartValue as to why this is
+    // currently necessary.
+    ASSERT(thread->zone() == zone);
+  }
+
+  // Walks [root_sexp_] and constructs a new FlowGraph.
+  FlowGraph* ParseFlowGraph();
+
+  const char* error_message() const { return error_message_; }
+  SExpression* error_sexp() const { return error_sexp_; }
+
+  // Prints the current error information to stderr and aborts.
+  DART_NORETURN void ReportError() const;
+
+ private:
+#define FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(M)                         \
+  M(FunctionEntry)                                                             \
+  M(GraphEntry)                                                                \
+  M(JoinEntry)                                                                 \
+  M(TargetEntry)
+
+#define FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(M)                        \
+  M(AllocateObject)                                                            \
+  M(Branch)                                                                    \
+  M(CheckNull)                                                                 \
+  M(CheckStackOverflow)                                                        \
+  M(Constant)                                                                  \
+  M(DebugStepCheck)                                                            \
+  M(Goto)                                                                      \
+  M(LoadField)                                                                 \
+  M(Parameter)                                                                 \
+  M(PushArgument)                                                              \
+  M(Return)                                                                    \
+  M(SpecialParameter)                                                          \
+  M(StaticCall)                                                                \
+  M(StoreInstanceField)                                                        \
+  M(StrictCompare)
+
+  // Helper methods for AllUnhandledInstructions.
+  static bool IsHandledInstruction(Instruction* inst);
+  static bool IsHandledConstant(const Object& obj);
+
+  // **GENERAL DESIGN NOTES FOR PARSING METHODS**
+  //
+  // For functions that take an SExpression or a subclass, they should return
+  // an error signal (false, nullptr, etc.) without changing the error state if
+  // passed in nullptr. This way, methods can be chained without intermediate
+  // checking.
+  //
+  // Also, for parsing methods for expressions that are known to be of a certain
+  // form, they will take the appropriate subclass of SExpression and assume
+  // that the form was already pre-checked by the caller. For forms that are
+  // tagged lists, this includes the fact that there is at least one element
+  // and the first element is a symbol. If the form can only have one possible
+  // tag, they also assume the tag has already been checked.
+
+  // Helper functions that do length/key exists checking and also check that
+  // the retrieved element is not nullptr. Notably, do not use these if the
+  // retrieved element is optional, to avoid changing the error state
+  // unnecessarily.
+  SExpression* Retrieve(SExpList* list, intptr_t index);
+  SExpression* Retrieve(SExpList* list, const char* key);
+
+  bool ParseConstantPool(SExpList* pool);
+  bool ParseEntries(SExpList* list);
+
+  using PushStack = ZoneGrowableArray<PushArgumentInstr*>;
+  using BlockWorklist = GrowableArray<intptr_t>;
+
+  // Starts parsing the contents of [list], where the blocks begin at position
+  // [pos] and [worklist] contains the blocks whose body instructions should
+  // be parsed first.
+  bool ParseBlocks(SExpList* list, intptr_t pos, BlockWorklist* worklist);
+
+  // Block parsing is split into two passes. This pass adds function entries
+  // to the flow graph and also parses initial definitions found in the Entries
+  // list. The block is added to the [block_map_] before returning.
+  BlockEntryInstr* ParseBlockHeader(SExpList* list,
+                                    intptr_t block_id,
+                                    SExpSymbol* tag);
+
+  // Expects [current_block_] to be set before calling.
+  bool ParseInitialDefinitions(SExpList* list);
+
+  // Expects [current_block_] to be set before calling.
+  // Takes the tagged list to parse and the index where parsing should start.
+  // Attempts to parse Phi definitions until the first non-Phi instruction.
+  bool ParsePhis(SExpList* list);
+
+  // Expects [current_block_] to be set before calling.
+  // Returns the position of the first non-Phi instruction in a block.
+  intptr_t SkipPhis(SExpList* list);
+
+  // Parses the deopt environment, Phi definitions for JoinEntrys, and the
+  // instructions in the body of the block. Adds the IDs of the block successors
+  // to the worklist, if any. [current_block_] and [pushed_stack_] must be set
+  // before calling.
+  bool ParseBlockContents(SExpList* list, BlockWorklist* worklist);
+
+  // Helper function used by ParseConstantPool, ParsePhis, and ParseDefinition.
+  // This handles all the extra information stored in (def ...) expressions,
+  // and also ensures the index of the definition is appropriately adjusted to
+  // match those found in the serialized form.
+  bool ParseDefinitionWithParsedBody(SExpList* list, Definition* def);
+
+  Definition* ParseDefinition(SExpList* list);
+  Instruction* ParseInstruction(SExpList* list);
+
+  struct EntryInfo {
+    intptr_t block_id;
+    intptr_t try_index;
+    intptr_t deopt_id;
+  };
+
+#define HANDLER_DECL(name)                                                     \
+  name##Instr* Deserialize##name(SExpList* list, const EntryInfo& info);
+
+  FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLER_DECL);
+
+#undef HANDLER_DECL
+
+  struct InstrInfo {
+    intptr_t deopt_id;
+    TokenPosition token_pos;
+  };
+
+  enum HandledInstruction {
+#define HANDLED_INST_DECL(name) kHandled##name,
+    FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_INST_DECL)
+#undef HANDLED_INST_DECL
+    // clang-format off
+    kHandledInvalid = -1,
+    // clang-format on
+  };
+
+#define HANDLE_CASE(name)                                                      \
+  if (strcmp(tag->value(), #name) == 0) return kHandled##name;
+  HandledInstruction HandledInstructionForTag(SExpSymbol* tag) {
+    ASSERT(tag != nullptr);
+    FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
+    return kHandledInvalid;
+  }
+#undef HANDLE_CASE
+
+#define HANDLER_DECL(name)                                                     \
+  name##Instr* Deserialize##name(SExpList* list, const InstrInfo& info);
+
+  FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLER_DECL);
+
+#undef HANDLER_DECL
+
+  // Parses [sexp] as a value form, that is, either the binding name for
+  // a definition as a symbol or the form (value <name> { ... }).
+  // If [allow_pending], then values for definitions not already in the
+  // [definition_map_] will be added to the [values_map_], otherwise,
+  // values for definitions not yet seen cause an error to be stored and
+  // nullptr to be returned.
+  Value* ParseValue(SExpression* sexp, bool allow_pending = true);
+  CompileType* ParseCompileType(SExpList* list);
+
+  // Parses [list] as an environment form: a list containing either binding
+  // names for definitions or a# for pushed arguments (where # is the depth
+  // of the argument from the top of the stack). Requires [pushed_stack_] to
+  // be set if any references to pushed arguments are found.
+  Environment* ParseEnvironment(SExpList* list);
+
+  // Parsing functions for which there are no good distinguished error
+  // values, so use out parameters and a boolean return instead.
+
+  // Parses a Dart value and returns a canonicalized result.
+  bool ParseDartValue(SExpression* sexp, Object* out);
+
+  // Helper function for ParseDartValue for parsing instances.
+  // Does not canonicalize (that is currently done in ParseDartValue), so
+  // do not call this method directly.
+  bool ParseInstance(SExpList* list, Instance* out);
+
+  bool ParseCanonicalName(SExpSymbol* sym, Object* out);
+
+  const Field& MayCloneField(const Field& field);
+  bool ParseSlot(SExpList* list, const Slot** out);
+
+  bool ParseBlockId(SExpSymbol* sym, intptr_t* out);
+  bool ParseSSATemp(SExpSymbol* sym, intptr_t* out);
+  bool ParseUse(SExpSymbol* sym, intptr_t* out);
+  bool ParseSymbolAsPrefixedInt(SExpSymbol* sym, char prefix, intptr_t* out);
+
+  // Helper function for creating a placeholder value when the definition
+  // has not yet been seen.
+  Value* AddNewPendingValue(intptr_t index);
+
+  // Similar helper, but where we already have a created value.
+  void AddPendingValue(intptr_t index, Value* val);
+
+  // Helper function for rebinding pending values once the definition has
+  // been located.
+  void FixPendingValues(intptr_t index, Definition* def);
+
+  // Creates a PushArgumentsArray of size [len] from [pushed_stack_] if there
+  // are enough and pops the fetched arguments from the stack.
+  //
+  // The [sexp] argument should be the serialized form of the instruction that
+  // needs the pushed arguments and is only used for error reporting.
+  PushArgumentsArray* FetchPushedArguments(SExpList* sexp, intptr_t len);
+
+  // Retrieves the block corresponding to the given block ID symbol from
+  // [block_map_]. Assumes all blocks have had their header parsed.
+  BlockEntryInstr* FetchBlock(SExpSymbol* sym);
+
+  // Checks that the pushed argument stacks for all predecessors of [succ_block]
+  // are the same as [curr_stack]. This check ensures that we can choose an
+  // arbitrary predecessor's pushed argument stack when parsing [succ_block]'s
+  // contents. [list] is used for error reporting.
+  bool AreStacksConsistent(SExpList* list,
+                           PushStack* curr_stack,
+                           BlockEntryInstr* succ_block);
+
+  // Utility functions for checking the shape of an S-expression.
+  // If these functions return nullptr for a non-null argument, they have the
+  // side effect of setting the stored error message.
+#define BASE_CHECK_DECL(name, type) SExp##name* Check##name(SExpression* sexp);
+  FOR_EACH_S_EXPRESSION(BASE_CHECK_DECL)
+#undef BASE_CHECK_DECL
+
+  // Checks whether [sexp] is a symbol with the given label.
+  bool IsTag(SExpression* sexp, const char* label);
+
+  // A version of CheckList that also checks that the list has at least one
+  // element and that the first element is a symbol. If [label] is non-null,
+  // then the initial symbol element is checked against it.
+  SExpList* CheckTaggedList(SExpression* sexp, const char* label = nullptr);
+
+  // Stores appropriate error information using the SExpression as the location
+  // and the rest of the arguments as an error message for the user.
+  void StoreError(SExpression* s, const char* fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+
+  Thread* thread() const { return thread_; }
+  Zone* zone() const { return zone_; }
+
+  Thread* const thread_;
+  Zone* const zone_;
+  SExpression* const root_sexp_;
+  const ParsedFunction* parsed_function_;
+
+  FlowGraph* flow_graph_ = nullptr;
+  BlockEntryInstr* current_block_ = nullptr;
+  intptr_t max_block_id_ = -1;
+  intptr_t max_ssa_index_ = -1;
+
+  // Map from block IDs to blocks. Does not contain an entry for block 0
+  // (the graph entry), since it is only used at known points and is already
+  // available via [flow_graph_].
+  IntMap<BlockEntryInstr*> block_map_;
+
+  // Map from block IDs to pushed argument stacks. Used for PushArgument
+  // instructions, environment parsing, and calls during block parsing. Also
+  // used to check that the final pushed argument stacks for predecessor blocks
+  // are consistent when parsing a JoinEntry.
+  IntMap<PushStack*> pushed_stack_map_;
+
+  // Map from variable indexes to definitions.
+  IntMap<Definition*> definition_map_;
+
+  // Map from variable indices to lists of values. The list of values are
+  // values that were parsed prior to the corresponding definition being found.
+  IntMap<ZoneGrowableArray<Value*>*> values_map_;
+
+  // Temporary handles used by functions that are not re-entrant or where the
+  // handle is not live after the re-entrant call. Comments show which handles
+  // are expected to only be used within a single method.
+  Class& instance_class_;           // ParseInstance
+  Field& instance_field_;           // ParseInstance
+  Object& instance_object_;         // ParseInstance
+  Class& name_class_;               // ParseCanonicalName
+  Field& name_field_;               // ParseCanonicalName
+  Function& name_function_;         // ParseCanonicalName
+  Library& name_library_;           // ParseCanonicalName
+  Class& value_class_;              // ParseDartValue
+  Object& value_object_;            // ParseDartValue
+  AbstractType& value_type_;        // ParseDartValue
+  TypeArguments& value_type_args_;  // ParseDartValue
+  // Uses of string handles tend to be immediate, so we only need one.
+  String& tmp_string_;
+
+  // Stores a message appropriate to surfacing to the user when an error
+  // occurs.
+  const char* error_message_ = nullptr;
+  // Stores the location of the deserialization error by containing the
+  // S-expression which caused the failure.
+  SExpression* error_sexp_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(FlowGraphDeserializer);
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 1729f42..72bc6b3 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -1036,15 +1036,16 @@
   __ pushl(EDI);
 
   // Load the thread object.
-  // Linking in AOT is not relevant here since we don't support AOT for IA32.
+  //
   // Create another frame to align the frame before continuing in "native" code.
   // If we were called by a trampoline, it has already loaded the thread.
+  ASSERT(!FLAG_precompiled_mode);  // No relocation for AOT linking.
   if (!NativeCallbackTrampolines::Enabled()) {
     __ EnterFrame(0);
     __ ReserveAlignedFrameSpace(compiler::target::kWordSize);
 
     __ movl(compiler::Address(SPREG, 0), compiler::Immediate(callback_id_));
-    __ movl(EAX, compiler::Immediate(reinterpret_cast<int64_t>(
+    __ movl(EAX, compiler::Immediate(reinterpret_cast<intptr_t>(
                      DLRT_GetThreadForNativeCallback)));
     __ call(EAX);
     __ movl(THR, EAX);
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index 36b4542..5369159 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -35,23 +35,48 @@
 
 void FlowGraphSerializer::SerializeToBuffer(const FlowGraph* flow_graph,
                                             TextBuffer* buffer) {
-  SerializeToBuffer(flow_graph->zone(), flow_graph, buffer);
+  SerializeToBuffer(Thread::Current()->zone(), flow_graph, buffer);
 }
 
 void FlowGraphSerializer::SerializeToBuffer(Zone* zone,
                                             const FlowGraph* flow_graph,
                                             TextBuffer* buffer) {
   ASSERT(buffer != nullptr);
-  FlowGraphSerializer serializer(zone, flow_graph);
-  auto const sexp = serializer.FlowGraphToSExp();
+  auto const sexp = SerializeToSExp(zone, flow_graph);
   if (FLAG_pretty_print_serialization) {
-    sexp->SerializeTo(serializer.zone(), buffer, initial_indent);
+    sexp->SerializeTo(zone, buffer, initial_indent);
   } else {
     sexp->SerializeToLine(buffer);
   }
   buffer->AddString("\n\n");
 }
 
+SExpression* FlowGraphSerializer::SerializeToSExp(const FlowGraph* flow_graph) {
+  return SerializeToSExp(Thread::Current()->zone(), flow_graph);
+}
+
+SExpression* FlowGraphSerializer::SerializeToSExp(Zone* zone,
+                                                  const FlowGraph* flow_graph) {
+  FlowGraphSerializer serializer(zone, flow_graph);
+  return serializer.FlowGraphToSExp();
+}
+
+#define KIND_STR(name) #name,
+static const char* block_entry_kind_tags[FlowGraphSerializer::kNumEntryKinds] =
+    {FOR_EACH_BLOCK_ENTRY_KIND(KIND_STR)};
+#undef KIND_STR
+
+FlowGraphSerializer::BlockEntryKind FlowGraphSerializer::BlockEntryTagToKind(
+    SExpSymbol* tag) {
+  if (tag == nullptr) return kTarget;
+  auto const str = tag->value();
+  for (intptr_t i = 0; i < kNumEntryKinds; i++) {
+    auto const current = block_entry_kind_tags[i];
+    if (strcmp(str, current) == 0) return static_cast<BlockEntryKind>(i);
+  }
+  return kInvalid;
+}
+
 void FlowGraphSerializer::AddBool(SExpList* sexp, bool b) {
   sexp->Add(new (zone()) SExpBool(b));
 }
@@ -101,7 +126,9 @@
   ASSERT(!obj.IsNull());
   if (obj.IsFunction()) {
     const auto& function = Function::Cast(obj);
-    tmp_string_ = function.UserVisibleName();
+    tmp_string_ = function.name();
+    // We only want private keys removed, no other changes.
+    tmp_string_ = String::RemovePrivateKey(tmp_string_);
     const char* function_name = tmp_string_.ToCString();
     // If this function is an inner closure then the parent points to its
     // containing function, which will also be part of the canonical name.
@@ -159,34 +186,41 @@
   return new (zone()) SExpSymbol(OS::SCreate(zone(), "%s", b.buf()));
 }
 
+SExpSymbol* FlowGraphSerializer::BlockEntryKindToTag(BlockEntryKind k) {
+  ASSERT(k >= 0 && k < kNumEntryKinds);
+  return new (zone()) SExpSymbol(block_entry_kind_tags[k]);
+}
+
+#define KIND_TAG(name) block_entry_kind_tags[k##name]
 SExpSymbol* FlowGraphSerializer::BlockEntryTag(const BlockEntryInstr* entry) {
   if (entry == nullptr) return nullptr;
   BlockEntryInstr* const to_test = const_cast<BlockEntryInstr*>(entry);
   if (to_test->IsGraphEntry()) {
-    return new (zone()) SExpSymbol("Graph");
+    return BlockEntryKindToTag(kGraph);
   }
   if (to_test->IsOsrEntry()) {
-    return new (zone()) SExpSymbol("OSR");
+    return BlockEntryKindToTag(kOSR);
   }
   if (to_test->IsCatchBlockEntry()) {
-    return new (zone()) SExpSymbol("Catch");
+    return BlockEntryKindToTag(kCatch);
   }
   if (to_test->IsIndirectEntry()) {
-    return new (zone()) SExpSymbol("Indirect");
+    return BlockEntryKindToTag(kIndirect);
   }
   if (to_test->IsFunctionEntry()) {
     if (entry == flow_graph()->graph_entry()->normal_entry()) {
-      return new (zone()) SExpSymbol("Normal");
+      return BlockEntryKindToTag(kNormal);
     }
     if (entry == flow_graph()->graph_entry()->unchecked_entry()) {
-      return new (zone()) SExpSymbol("Unchecked");
+      return BlockEntryKindToTag(kUnchecked);
     }
   }
   if (to_test->IsJoinEntry()) {
-    return new (zone()) SExpSymbol("Join");
+    return BlockEntryKindToTag(kJoin);
   }
   return nullptr;
 }
+#undef KIND_TAG
 
 SExpression* FlowGraphSerializer::FunctionEntryToSExp(BlockEntryInstr* entry) {
   if (entry == nullptr) return nullptr;
@@ -199,6 +233,11 @@
       sexp->Add(initial_defs->At(i)->ToSExpression(this));
     }
   }
+
+  // Also include the extra info here, to avoid having to find the
+  // corresponding block to get it.
+  entry->BlockEntryInstr::AddExtraInfoToSExpression(sexp, this);
+
   return sexp;
 }
 
@@ -325,6 +364,7 @@
   ASSERT(t.IsType());
   AddSymbol(sexp, "Type");
   const auto& typ = Type::Cast(t);
+  ASSERT(typ.IsFinalized());
   if (typ.HasTypeClass()) {
     type_class_ = typ.type_class();
     // This avoids re-entry as long as serializing a class doesn't involve
@@ -450,8 +490,9 @@
       AddExtraSymbol(sexp, "native_name", tmp_string_.ToCString());
     }
   }
-  if (FLAG_verbose_flow_graph_serialization) {
-    AddExtraSymbol(sexp, "kind", Function::KindToCString(func.kind()));
+  if (func.kind() != RawFunction::Kind::kRegularFunction ||
+      FLAG_verbose_flow_graph_serialization) {
+    AddExtraSymbol(sexp, "kind", RawFunction::KindToCString(func.kind()));
   }
   function_type_args_ = func.type_parameters();
   if (auto const ta_sexp = NonEmptyTypeArgumentsToSExp(function_type_args_)) {
@@ -474,6 +515,10 @@
     array_elem = arr.At(i);
     sexp->Add(DartValueToSExp(array_elem));
   }
+  array_type_args_ = arr.GetTypeArguments();
+  if (auto const type_args_sexp = TypeArgumentsToSExp(array_type_args_)) {
+    sexp->AddExtra("type_args", type_args_sexp);
+  }
   return sexp;
 }
 
@@ -485,6 +530,10 @@
   if (auto const func = FunctionToSExp(closure_function_)) {
     sexp->Add(func);
   }
+  closure_context_ = c.context();
+  if (auto const context = ContextToSExp(closure_context_)) {
+    sexp->AddExtra("context", context);
+  }
   closure_type_args_ = c.function_type_arguments();
   if (auto const type_args = NonEmptyTypeArgumentsToSExp(closure_type_args_)) {
     sexp->AddExtra("func_type_args", type_args);
@@ -500,6 +549,23 @@
   return sexp;
 }
 
+SExpression* FlowGraphSerializer::ContextToSExp(const Context& c) {
+  if (c.IsNull()) return nullptr;
+  auto sexp = new (zone()) SExpList(zone());
+  AddSymbol(sexp, "Context");
+  for (intptr_t i = 0; i < c.num_variables(); i++) {
+    context_elem_ = c.At(i);
+    auto const elem_sexp = DartValueToSExp(context_elem_);
+    if (elem_sexp == nullptr) return nullptr;
+    sexp->Add(elem_sexp);
+  }
+  context_parent_ = c.parent();
+  if (auto const parent_sexp = ContextToSExp(context_parent_)) {
+    sexp->AddExtra("parent", parent_sexp);
+  }
+  return sexp;
+}
+
 SExpression* FlowGraphSerializer::ObjectToSExp(const Object& dartval) {
   if (dartval.IsNull()) {
     return new (zone()) SExpSymbol("null");
@@ -603,10 +669,13 @@
 void BlockEntryInstr::AddExtraInfoToSExpression(SExpList* sexp,
                                                 FlowGraphSerializer* s) const {
   Instruction::AddExtraInfoToSExpression(sexp, s);
+  if (try_index() != kInvalidTryIndex) {
+    s->AddExtraInteger(sexp, "try_index", try_index());
+  }
+  if (auto const entry_tag = s->BlockEntryTag(this)) {
+    sexp->AddExtra("block_type", entry_tag);
+  }
   if (FLAG_verbose_flow_graph_serialization) {
-    if (auto const entry_tag = s->BlockEntryTag(this)) {
-      sexp->AddExtra("block_type", entry_tag);
-    }
     if (PredecessorCount() > 0) {
       auto const preds = new (s->zone()) SExpList(s->zone());
       for (intptr_t i = 0; i < PredecessorCount(); i++) {
@@ -688,6 +757,7 @@
 void SpecialParameterInstr::AddOperandsToSExpression(
     SExpList* sexp,
     FlowGraphSerializer* s) const {
+  ASSERT(kind() < SpecialParameterInstr::kNumKinds);
   s->AddSymbol(sexp, KindToCString(kind()));
 }
 
@@ -713,30 +783,13 @@
   sexp->Add(s->LocalVariableToSExp(local()));
 }
 
-static const char* SlotKindToCString(Slot::Kind kind) {
-  switch (kind) {
-    case Slot::Kind::kDartField:
-      return "DartField";
-    case Slot::Kind::kCapturedVariable:
-      return "CapturedVariable";
-    case Slot::Kind::kTypeArguments:
-      return "TypeArguments";
-    default:
-      return "NativeSlot";
-  }
-}
-
 SExpression* FlowGraphSerializer::SlotToSExp(const Slot& slot) {
   auto sexp = new (zone()) SExpList(zone());
   AddSymbol(sexp, "Slot");
   AddInteger(sexp, slot.offset_in_bytes());
-  if (FLAG_verbose_flow_graph_serialization) {
-    AddExtraSymbol(sexp, "kind", SlotKindToCString(slot.kind()));
-    if (slot.IsDartField()) {
-      sexp->AddExtra("field", DartValueToSExp(slot.field()));
-    } else {
-      AddExtraString(sexp, "name", slot.Name());
-    }
+  AddExtraSymbol(sexp, "kind", Slot::KindToCString(slot.kind()));
+  if (slot.IsDartField()) {
+    sexp->AddExtra("field", DartValueToSExp(slot.field()));
   }
   return sexp;
 }
@@ -755,6 +808,23 @@
   sexp->Add(value()->ToSExpression(s));
 }
 
+void StoreInstanceFieldInstr::AddExtraInfoToSExpression(
+    SExpList* sexp,
+    FlowGraphSerializer* s) const {
+  if (is_initialization_ || FLAG_verbose_flow_graph_serialization) {
+    s->AddExtraBool(sexp, "is_init", is_initialization_);
+  }
+  if (emit_store_barrier_ != kNoStoreBarrier ||
+      FLAG_verbose_flow_graph_serialization) {
+    // Make sure that we aren't seeing a new value added to the StoreBarrierType
+    // enum that isn't handled by the serializer.
+    ASSERT(emit_store_barrier_ == kNoStoreBarrier ||
+           emit_store_barrier_ == kEmitStoreBarrier);
+    s->AddExtraBool(sexp, "emit_barrier",
+                    emit_store_barrier_ != kNoStoreBarrier);
+  }
+}
+
 void LoadIndexedUnsafeInstr::AddExtraInfoToSExpression(
     SExpList* sexp,
     FlowGraphSerializer* s) const {
@@ -779,6 +849,15 @@
   Instruction::AddOperandsToSExpression(sexp, s);
 }
 
+void StrictCompareInstr::AddExtraInfoToSExpression(
+    SExpList* sexp,
+    FlowGraphSerializer* s) const {
+  Instruction::AddExtraInfoToSExpression(sexp, s);
+  if (needs_number_check_ || FLAG_verbose_flow_graph_serialization) {
+    s->AddExtraBool(sexp, "needs_check", needs_number_check_);
+  }
+}
+
 void DoubleTestOpInstr::AddOperandsToSExpression(SExpList* sexp,
                                                  FlowGraphSerializer* s) const {
   const bool negated = kind() != Token::kEQ;
@@ -800,6 +879,17 @@
   sexp->Add(s->BlockIdToSExp(successor()->block_id()));
 }
 
+void DebugStepCheckInstr::AddExtraInfoToSExpression(
+    SExpList* sexp,
+    FlowGraphSerializer* s) const {
+  if (stub_kind_ != RawPcDescriptors::kAnyKind ||
+      FLAG_verbose_flow_graph_serialization) {
+    auto const stub_kind_name = RawPcDescriptors::KindToCString(stub_kind_);
+    ASSERT(stub_kind_name != nullptr);
+    s->AddExtraSymbol(sexp, "stub_kind", stub_kind_name);
+  }
+}
+
 void TailCallInstr::AddOperandsToSExpression(SExpList* sexp,
                                              FlowGraphSerializer* s) const {
   if (auto const code = s->DartValueToSExp(code_)) {
@@ -815,8 +905,8 @@
   }
 }
 
-template <>
-void TemplateDartCall<0l>::AddExtraInfoToSExpression(
+template <intptr_t kInputCount>
+void TemplateDartCall<kInputCount>::AddExtraInfoToSExpression(
     SExpList* sexp,
     FlowGraphSerializer* s) const {
   Instruction::AddExtraInfoToSExpression(sexp, s);
@@ -824,17 +914,26 @@
     s->AddExtraInteger(sexp, "type_args_len", type_args_len());
   }
   s->AddExtraInteger(sexp, "args_len", ArgumentCountWithoutTypeArgs());
+  if (this->CallCount() > 0 || FLAG_verbose_flow_graph_serialization) {
+    s->AddExtraInteger(sexp, "call_count", this->CallCount());
+  }
+  const auto& arg_names = argument_names();
+  if (!arg_names.IsNull()) {
+    auto arg_names_sexp = new (s->zone()) SExpList(s->zone());
+    auto& str = String::Handle(s->zone());
+    for (intptr_t i = 0; i < arg_names.Length(); i++) {
+      str = String::RawCast(arg_names.At(i));
+      arg_names_sexp->Add(s->ObjectToSExp(str));
+    }
+    sexp->AddExtra("arg_names", arg_names_sexp);
+  }
 }
 
-template <>
-void TemplateDartCall<1l>::AddExtraInfoToSExpression(
-    SExpList* sexp,
-    FlowGraphSerializer* s) const {
-  Instruction::AddExtraInfoToSExpression(sexp, s);
-  if (type_args_len() > 0 || FLAG_verbose_flow_graph_serialization) {
-    s->AddExtraInteger(sexp, "type_args_len", type_args_len());
-  }
-  s->AddExtraInteger(sexp, "args_len", ArgumentCountWithoutTypeArgs());
+void ClosureCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
+                                                 FlowGraphSerializer* s) const {
+  // For now, just here to ensure TemplateDartCall<1>::AddExtraInfoToSExpression
+  // gets instantiated.
+  TemplateDartCall<1>::AddExtraInfoToSExpression(sexp, s);
 }
 
 void StaticCallInstr::AddOperandsToSExpression(SExpList* sexp,
@@ -844,6 +943,18 @@
   }
 }
 
+void StaticCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
+                                                FlowGraphSerializer* s) const {
+  TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
+
+  if (rebind_rule_ != ICData::kInstance ||
+      FLAG_verbose_flow_graph_serialization) {
+    auto const str = ICData::RebindRuleToCString(rebind_rule_);
+    ASSERT(str != nullptr);
+    s->AddExtraSymbol(sexp, "rebind_rule", str);
+  }
+}
+
 void InstanceCallInstr::AddOperandsToSExpression(SExpList* sexp,
                                                  FlowGraphSerializer* s) const {
   if (auto const target = s->DartValueToSExp(interface_target())) {
@@ -982,6 +1093,18 @@
   if (in_loop() || FLAG_verbose_flow_graph_serialization) {
     s->AddExtraInteger(sexp, "loop_depth", loop_depth());
   }
+  if (kind_ != kOsrAndPreemption) {
+    ASSERT(kind_ == kOsrOnly);
+    s->AddExtraSymbol(sexp, "kind", "OsrOnly");
+  }
+}
+
+void CheckNullInstr::AddExtraInfoToSExpression(SExpList* sexp,
+                                               FlowGraphSerializer* s) const {
+  Instruction::AddExtraInfoToSExpression(sexp, s);
+  if (!function_name_.IsNull()) {
+    s->AddExtraString(sexp, "function_name", function_name_.ToCString());
+  }
 }
 
 SExpression* Value::ToSExpression(FlowGraphSerializer* s) const {
@@ -1013,6 +1136,8 @@
 
 void CompileType::AddExtraInfoToSExpression(SExpList* sexp,
                                             FlowGraphSerializer* s) const {
+  // TODO(sstrickl): Currently we only print out nullable if it's false
+  // (or during verbose printing). Switch this when NNBD is the standard.
   if (!is_nullable() || FLAG_verbose_flow_graph_serialization) {
     s->AddExtraBool(sexp, "nullable", is_nullable());
   }
@@ -1032,7 +1157,7 @@
 
   for (intptr_t i = 0; i < values_.length(); ++i) {
     if (values_[i]->definition()->IsPushArgument()) {
-      s->AddSymbol(sexp, OS::SCreate(s->zone(), "arg[%" Pd "]", arg_count++));
+      s->AddSymbol(sexp, OS::SCreate(s->zone(), "a%" Pd "", arg_count++));
     } else {
       sexp->Add(values_[i]->ToSExpression(s));
     }
@@ -1043,7 +1168,11 @@
     ASSERT(locations_ == nullptr || locations_[i].IsInvalid());
   }
   if (outer_ != NULL) {
-    sexp->Add(outer_->ToSExpression(s));
+    auto outer_sexp = outer_->ToSExpression(s)->AsList();
+    if (outer_->deopt_id_ != DeoptId::kNone) {
+      s->AddExtraInteger(outer_sexp, "deopt_id", outer_->deopt_id_);
+    }
+    sexp->AddExtra("outer", outer_sexp);
   }
   return sexp;
 }
diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h
index 3390a53..753ce49 100644
--- a/runtime/vm/compiler/backend/il_serializer.h
+++ b/runtime/vm/compiler/backend/il_serializer.h
@@ -20,11 +20,38 @@
 // Flow graph serialization.
 class FlowGraphSerializer : ValueObject {
  public:
+#define FOR_EACH_BLOCK_ENTRY_KIND(M)                                           \
+  M(Target)                                                                    \
+  M(Join)                                                                      \
+  M(Graph)                                                                     \
+  M(Normal)                                                                    \
+  M(Unchecked)                                                                 \
+  M(OSR)                                                                       \
+  M(Catch)                                                                     \
+  M(Indirect)
+
+  enum BlockEntryKind {
+#define KIND_DECL(name) k##name,
+    FOR_EACH_BLOCK_ENTRY_KIND(KIND_DECL)
+#undef KIND_DECL
+    // clang-format off
+    kNumEntryKinds,
+    kInvalid = -1,
+    // clang-format on
+  };
+
+  // Special case: returns kTarget for a nullptr input.
+  static BlockEntryKind BlockEntryTagToKind(SExpSymbol* tag);
+  SExpSymbol* BlockEntryKindToTag(BlockEntryKind k);
+  static bool BlockEntryKindHasInitialDefs(BlockEntryKind kind);
+
   static void SerializeToBuffer(const FlowGraph* flow_graph,
                                 TextBuffer* buffer);
   static void SerializeToBuffer(Zone* zone,
                                 const FlowGraph* flow_graph,
                                 TextBuffer* buffer);
+  static SExpression* SerializeToSExp(const FlowGraph* flow_graph);
+  static SExpression* SerializeToSExp(Zone* zone, const FlowGraph* flow_graph);
 
   const FlowGraph* flow_graph() const { return flow_graph_; }
   Zone* zone() const { return zone_; }
@@ -45,6 +72,7 @@
   SExpression* ArrayToSExp(const Array& arr);
   SExpression* ClassToSExp(const Class& cls);
   SExpression* ClosureToSExp(const Closure& c);
+  SExpression* ContextToSExp(const Context& c);
   SExpression* CodeToSExp(const Code& c);
   SExpression* FieldToSExp(const Field& f);
   SExpression* FunctionToSExp(const Function& f);
@@ -83,9 +111,13 @@
       : flow_graph_(ASSERT_NOTNULL(flow_graph)),
         zone_(zone),
         tmp_string_(String::Handle(zone_)),
+        array_type_args_((TypeArguments::Handle(zone_))),
+        closure_context_(Context::Handle(zone_)),
         closure_function_(Function::Handle(zone_)),
         closure_type_args_(TypeArguments::Handle(zone_)),
         code_owner_(Object::Handle(zone_)),
+        context_parent_(Context::Handle(zone_)),
+        context_elem_(Object::Handle(zone_)),
         function_type_args_(TypeArguments::Handle(zone_)),
         instance_field_(Field::Handle(zone_)),
         instance_type_args_(TypeArguments::Handle(zone_)),
@@ -94,7 +126,11 @@
         serialize_parent_(Function::Handle(zone_)),
         type_arguments_elem_(AbstractType::Handle(zone_)),
         type_class_(Class::Handle(zone_)),
-        type_ref_type_(AbstractType::Handle(zone_)) {}
+        type_ref_type_(AbstractType::Handle(zone_)) {
+    // Double-check that the zone in the flow graph is a parent of the
+    // zone we'll be using for serialization.
+    ASSERT(flow_graph->zone()->ContainsNestedZone(zone));
+  }
 
   static const char* const initial_indent;
 
@@ -121,9 +157,13 @@
   // DartValueToSExp with a sub-element of type Object, but any call to a
   // FlowGraphSerializer method that may eventually enter one of the methods
   // listed below should be examined with care.
+  TypeArguments& array_type_args_;     // ArrayToSExp
+  Context& closure_context_;           // ClosureToSExp
   Function& closure_function_;         // ClosureToSExp
   TypeArguments& closure_type_args_;   // ClosureToSExp
   Object& code_owner_;                 // CodeToSExp
+  Context& context_parent_;            // ContextToSExp
+  Object& context_elem_;               // ContextToSExp
   TypeArguments& function_type_args_;  // FunctionToSExp
   Field& instance_field_;              // InstanceToSExp
   TypeArguments& instance_type_args_;  // InstanceToSExp
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 0bc24f1..bdc039a 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -114,9 +114,9 @@
     }
 
     if (passes.size() > 0) {
-      CompilerPass::RunPipelineWithPasses(pass_state_, passes);
+      flow_graph_ = CompilerPass::RunPipelineWithPasses(pass_state_, passes);
     } else {
-      CompilerPass::RunPipeline(mode_, pass_state_);
+      flow_graph_ = CompilerPass::RunPipeline(mode_, pass_state_);
     }
   }
 
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index d65b984..c7612ed 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1024,10 +1024,6 @@
 }
 
 void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (FLAG_precompiled_mode) {
-    UNREACHABLE();
-  }
-
   __ Bind(compiler->GetJumpLabel(this));
 
   // Create a dummy frame holding the pushed arguments. This simplifies
@@ -1055,9 +1051,38 @@
   __ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters,
                    CallingConventions::kCalleeSaveXmmRegisters);
 
-  // Load the thread object.
-  // TODO(35765): Fix linking issue on AOT.
-  //
+  // Load the address of DLRT_GetThreadForNativeCallback without using Thread.
+  if (FLAG_precompiled_mode) {
+    compiler::Label skip_reloc;
+    __ jmp(&skip_reloc);
+    compiler->InsertBSSRelocation(
+        BSS::Relocation::DRT_GetThreadForNativeCallback);
+    const intptr_t reloc_end = __ CodeSize();
+    __ Bind(&skip_reloc);
+
+    const intptr_t kLeaqLength = 7;
+    __ leaq(RAX, compiler::Address::AddressRIPRelative(
+                     -kLeaqLength - compiler::target::kWordSize));
+    ASSERT((__ CodeSize() - reloc_end) == kLeaqLength);
+
+    // RAX holds the address of the relocation.
+    __ movq(RCX, compiler::Address(RAX, 0));
+
+    // RCX holds the relocation itself: RAX - bss_start.
+    // RAX = RAX + (bss_start - RAX) = bss_start
+    __ addq(RAX, RCX);
+
+    // RAX holds the start of the BSS section.
+    // Load the "get-thread" routine: *bss_start.
+    __ movq(RAX, compiler::Address(RAX, 0));
+  } else if (!NativeCallbackTrampolines::Enabled()) {
+    // In JIT mode, we can just paste the address of the runtime entry into the
+    // generated code directly. This is not a problem since we don't save
+    // callbacks into JIT snapshots.
+    __ movq(RAX, compiler::Immediate(reinterpret_cast<intptr_t>(
+                     DLRT_GetThreadForNativeCallback)));
+  }
+
   // Create another frame to align the frame before continuing in "native" code.
   // If we were called by a trampoline, it has already loaded the thread.
   if (!NativeCallbackTrampolines::Enabled()) {
@@ -1066,8 +1091,6 @@
 
     COMPILE_ASSERT(RAX != CallingConventions::kArg1Reg);
     __ movq(CallingConventions::kArg1Reg, compiler::Immediate(callback_id_));
-    __ movq(RAX, compiler::Immediate(reinterpret_cast<int64_t>(
-                     DLRT_GetThreadForNativeCallback)));
     __ CallCFunction(RAX);
     __ movq(THR, RAX);
 
@@ -4779,7 +4802,7 @@
 void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   ASSERT((op_kind() == MethodRecognizer::kMathMin) ||
          (op_kind() == MethodRecognizer::kMathMax));
-  const intptr_t is_min = (op_kind() == MethodRecognizer::kMathMin);
+  const bool is_min = op_kind() == MethodRecognizer::kMathMin;
   if (result_cid() == kDoubleCid) {
     compiler::Label done, returns_nan, are_equal;
     XmmRegister left = locs()->in(0).fpu_reg();
@@ -5690,6 +5713,64 @@
                                  Register out) {
   ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
 
+  // Special case 64-bit div/mod by compile-time constant. Note that various
+  // special constants (such as powers of two) should have been optimized
+  // earlier in the pipeline. Div or mod by zero falls into general code
+  // to implement the exception.
+  if (auto c = instruction->right()->definition()->AsConstant()) {
+    if (c->value().IsInteger()) {
+      const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
+      if (divisor <= -2 || divisor >= 2) {
+        // For x DIV c or x MOD c: use magic operations.
+        compiler::Label pos;
+        int64_t magic = 0;
+        int64_t shift = 0;
+        Utils::CalculateMagicAndShiftForDivRem(divisor, &magic, &shift);
+        // RDX:RAX = magic * numerator.
+        ASSERT(left == RAX);
+        __ MoveRegister(TMP, RAX);  // save numerator
+        __ LoadImmediate(RAX, compiler::Immediate(magic));
+        __ imulq(TMP);
+        // RDX +/-= numerator.
+        if (divisor > 0 && magic < 0) {
+          __ addq(RDX, TMP);
+        } else if (divisor < 0 && magic > 0) {
+          __ subq(RDX, TMP);
+        }
+        // Shift if needed.
+        if (shift != 0) {
+          __ sarq(RDX, compiler::Immediate(shift));
+        }
+        // RDX += 1 if RDX < 0.
+        __ movq(RAX, RDX);
+        __ shrq(RDX, compiler::Immediate(63));
+        __ addq(RDX, RAX);
+        // Finalize DIV or MOD.
+        if (op_kind == Token::kTRUNCDIV) {
+          ASSERT(out == RAX && tmp == RDX);
+          __ movq(RAX, RDX);
+        } else {
+          ASSERT(out == RDX && tmp == RAX);
+          __ movq(RAX, TMP);
+          __ LoadImmediate(TMP, compiler::Immediate(divisor));
+          __ imulq(RDX, TMP);
+          __ subq(RAX, RDX);
+          // Compensate for Dart's Euclidean view of MOD.
+          __ testq(RAX, RAX);
+          __ j(GREATER_EQUAL, &pos);
+          if (divisor > 0) {
+            __ addq(RAX, TMP);
+          } else {
+            __ subq(RAX, TMP);
+          }
+          __ Bind(&pos);
+          __ movq(RDX, RAX);
+        }
+        return;
+      }
+    }
+  }
+
   // Prepare a slow path.
   Range* right_range = instruction->right()->definition()->range();
   Int64DivideSlowPath* slow_path = new (Z) Int64DivideSlowPath(
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 8f5492a..2a18c66 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -979,21 +979,6 @@
       // Install bailout jump.
       LongJumpScope jump;
       if (setjmp(*jump.Set()) == 0) {
-        Isolate* isolate = Isolate::Current();
-        // Makes sure no classes are loaded during parsing in background.
-        const intptr_t loading_invalidation_gen_at_start =
-            isolate->loading_invalidation_gen();
-
-        if (Compiler::IsBackgroundCompilation()) {
-          if ((loading_invalidation_gen_at_start !=
-               isolate->loading_invalidation_gen())) {
-            // Loading occured while parsing. We need to abort here because
-            // state changed while compiling.
-            Compiler::AbortBackgroundCompilation(
-                DeoptId::kNone, "Loading occured while parsing in inliner");
-          }
-        }
-
         // Load IC data for the callee.
         ZoneGrowableArray<const ICData*>* ic_data_array =
             new (Z) ZoneGrowableArray<const ICData*>();
@@ -1255,10 +1240,6 @@
           caller_graph()->parsed_function().AddToGuardedFields(
               callee_guarded_fields[i]);
         }
-        // When inlined, we add the deferred prefixes of the callee to the
-        // caller's list of deferred prefixes.
-        caller_graph()->AddToDeferredPrefixes(
-            callee_graph->deferred_prefixes());
 
         FlowGraphInliner::SetInliningId(
             callee_graph,
@@ -1910,6 +1891,7 @@
         // Unshared.  Graft the normal entry on after the check class
         // instruction.
         auto target = callee_entry->AsGraphEntry()->normal_entry();
+        ASSERT(cursor != nullptr);
         cursor->LinkTo(target->next());
         target->ReplaceAsPredecessorWith(current_block);
         // Unuse all inputs of the graph entry and the normal entry. They are
@@ -1970,6 +1952,7 @@
             new TargetEntryInstr(AllocateBlockId(), try_idx, DeoptId::kNone);
         below_target->InheritDeoptTarget(zone(), call_);
         current_block->AddDominatedBlock(below_target);
+        ASSERT(cursor != nullptr);  // read before overwrite
         cursor = current_block = below_target;
         *branch_top->true_successor_address() = below_target;
 
@@ -1987,9 +1970,9 @@
       }
 
       branch->InheritDeoptTarget(zone(), call_);
-      cursor = AppendInstruction(cursor, branch);
+      AppendInstruction(cursor, branch);
+      cursor = nullptr;
       current_block->set_last_instruction(branch);
-      cursor = NULL;
 
       // 2. Handle a match by linking to the inlined body.  There are three
       // cases (unshared, shared first predecessor, and shared subsequent
@@ -3322,15 +3305,16 @@
     ForwardInstructionIterator* iterator,
     InstanceCallInstr* call,
     SpeculativeInliningPolicy* policy) {
-  Function& target = Function::Handle(Z);
-  GrowableArray<intptr_t> class_ids;
-  call->ic_data()->GetCheckAt(0, &class_ids, &target);
-  const intptr_t receiver_cid = class_ids[0];
+  const CallTargets& targets = call->Targets();
+  ASSERT(targets.IsMonomorphic());
+  const intptr_t receiver_cid = targets.MonomorphicReceiverCid();
+  const Function& target = targets.FirstTarget();
+  const auto exactness = targets.MonomorphicExactness();
+  ExactnessInfo exactness_info{exactness.IsExact(), false};
+
   FunctionEntryInstr* entry = nullptr;
   Instruction* last = nullptr;
   Definition* result = nullptr;
-  auto exactness = call->ic_data()->GetExactnessAt(0);
-  ExactnessInfo exactness_info{exactness.IsExact(), false};
   if (FlowGraphInliner::TryInlineRecognizedMethod(
           flow_graph, receiver_cid, target, call,
           call->Receiver()->definition(), call->token_pos(), call->ic_data(),
@@ -3353,8 +3337,7 @@
     switch (check) {
       case FlowGraph::ToCheck::kCheckCid: {
         Instruction* check_class = flow_graph->CreateCheckClass(
-            call->Receiver()->definition(),
-            *Cids::CreateAndExpand(Z, *call->ic_data(), 0), call->deopt_id(),
+            call->Receiver()->definition(), targets, call->deopt_id(),
             call->token_pos());
         flow_graph->InsertBefore(call, check_class, call->env(),
                                  FlowGraph::kEffect);
@@ -3384,7 +3367,7 @@
     }
     // Replace all uses of this definition with the result.
     if (call->HasUses()) {
-      ASSERT(result->HasSSATemp());
+      ASSERT(result != nullptr && result->HasSSATemp());
       call->ReplaceUsesWith(result);
     }
     // Finally insert the sequence other definition in place of this one in the
@@ -3997,16 +3980,12 @@
     case MethodRecognizer::kGrowableArraySetData:
       ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
              ((receiver_cid == kDynamicCid) && call->IsStaticCall()));
-      ASSERT(call->IsStaticCall() ||
-             (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
       return InlineGrowableArraySetter(
           flow_graph, Slot::GrowableObjectArray_data(), kEmitStoreBarrier, call,
           receiver, graph_entry, entry, last, result);
     case MethodRecognizer::kGrowableArraySetLength:
       ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
              ((receiver_cid == kDynamicCid) && call->IsStaticCall()));
-      ASSERT(call->IsStaticCall() ||
-             (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
       return InlineGrowableArraySetter(
           flow_graph, Slot::GrowableObjectArray_length(), kNoStoreBarrier, call,
           receiver, graph_entry, entry, last, result);
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index 66101af..b196088 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -603,7 +603,8 @@
 
     // Check if any values live into the loop can be spilled for free.
     if (block->IsLoopHeader()) {
-      current_interference_set = NULL;
+      ASSERT(loop_info != nullptr);
+      current_interference_set = nullptr;
       for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); !it.Done();
            it.Advance()) {
         LiveRange* range = GetLiveRange(it.Current());
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index 638fc84..b6e7777 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -572,7 +572,7 @@
 
   void AddAllNonReservedRegisters(bool include_fpu_registers) {
     for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
-      if (kReservedCpuRegisters & (1 << i)) continue;
+      if ((kReservedCpuRegisters & (1 << i)) != 0u) continue;
       Add(Location::RegisterLocation(static_cast<Register>(i)));
     }
 
diff --git a/runtime/vm/compiler/backend/loops.cc b/runtime/vm/compiler/backend/loops.cc
index a641557..8c046a6 100644
--- a/runtime/vm/compiler/backend/loops.cc
+++ b/runtime/vm/compiler/backend/loops.cc
@@ -876,9 +876,9 @@
     num_blocks++;
   }
   f.Print("#blocks=%" Pd, num_blocks);
-  if (outer_) f.Print(" outer=%" Pd, outer_->id_);
-  if (inner_) f.Print(" inner=%" Pd, inner_->id_);
-  if (next_) f.Print(" next=%" Pd, next_->id_);
+  if (outer_ != nullptr) f.Print(" outer=%" Pd, outer_->id_);
+  if (inner_ != nullptr) f.Print(" inner=%" Pd, inner_->id_);
+  if (next_ != nullptr) f.Print(" next=%" Pd, next_->id_);
   f.Print(" [");
   for (intptr_t i = 0, n = back_edges_.length(); i < n; i++) {
     f.Print(" B%" Pd, back_edges_[i]->block_id());
diff --git a/runtime/vm/compiler/backend/sexpression.cc b/runtime/vm/compiler/backend/sexpression.cc
index 53077b7..a314abf 100644
--- a/runtime/vm/compiler/backend/sexpression.cc
+++ b/runtime/vm/compiler/backend/sexpression.cc
@@ -19,6 +19,16 @@
   return sexp;
 }
 
+const char* SExpression::ToCString(Zone* zone) const {
+  TextBuffer buf(1 * KB);
+  SerializeToLine(&buf);
+  auto const buf_len = buf.length();
+  char* ret = zone->Alloc<char>(buf_len + 1);
+  strncpy(ret, buf.buf(), buf_len);
+  ret[buf_len] = '\0';
+  return ret;
+}
+
 bool SExpBool::Equals(SExpression* sexp) const {
   if (!sexp->IsBool()) return false;
   return this->value() == sexp->AsBool()->value();
@@ -112,7 +122,7 @@
   const intptr_t leading_length = leading_space ? 1 : 0;
 
   if ((leading_length + single_line_width) < remaining) {
-    if (leading_space != 0) buffer->AddChar(' ');
+    if (leading_space) buffer->AddChar(' ');
     buffer->AddString(line_buffer->buf());
     line_buffer->Clear();
     return remaining - (leading_length + single_line_width);
@@ -498,7 +508,7 @@
 SExpParser::Token* SExpParser::GetNextToken() {
   intptr_t start_pos = cur_pos_;
   while (start_pos < buffer_size_) {
-    if (!isspace(buffer_[start_pos])) break;
+    if (isspace(buffer_[start_pos]) == 0) break;
     start_pos++;
   }
   if (start_pos >= buffer_size_) return nullptr;
@@ -572,7 +582,7 @@
     }
     // If we find a character that can't appear in a number, then fall back
     // to symbol-ness.
-    if (!isdigit(start[len])) type = kSymbol;
+    if (isdigit(start[len]) == 0) type = kSymbol;
     len++;
   }
   cur_pos_ = start_pos + len;
@@ -605,7 +615,7 @@
 }
 
 bool SExpParser::IsSymbolContinue(char c) {
-  return !isspace(c) && c != '(' && c != ')' && c != ',' && c != '{' &&
+  return (isspace(c) == 0) && c != '(' && c != ')' && c != ',' && c != '{' &&
          c != '}' && c != '"';
 }
 
diff --git a/runtime/vm/compiler/backend/sexpression.h b/runtime/vm/compiler/backend/sexpression.h
index 9636b19..4a7d67e 100644
--- a/runtime/vm/compiler/backend/sexpression.h
+++ b/runtime/vm/compiler/backend/sexpression.h
@@ -9,7 +9,6 @@
 
 #include "vm/allocation.h"
 #include "vm/growable_array.h"
-#include "vm/hash.h"
 #include "vm/hash_map.h"
 #include "vm/zone.h"
 
@@ -61,6 +60,7 @@
   static intptr_t const kInvalidPos = -1;
 
   static SExpression* FromCString(Zone* zone, const char* cstr);
+  const char* ToCString(Zone* zone) const;
   intptr_t start() const { return start_; }
 
 #define S_EXPRESSION_TYPE_CHECK(name, value_type)                              \
@@ -132,36 +132,7 @@
   explicit SExpList(Zone* zone, intptr_t start = kInvalidPos)
       : SExpression(start), contents_(zone, 2), extra_info_(zone) {}
 
-  template <typename V>
-  class CStringPointerKeyValueTrait {
-   public:
-    typedef const char* Key;
-    typedef V Value;
-
-    struct Pair {
-      Key key;
-      Value value;
-      Pair() : key(NULL), value() {}
-      Pair(const Key key, const Value& value) : key(key), value(value) {}
-      Pair(const Pair& other) : key(other.key), value(other.value) {}
-    };
-
-    static Key KeyOf(Pair kv) { return kv.key; }
-    static Value ValueOf(Pair kv) { return kv.value; }
-    static intptr_t Hashcode(Key key) {
-      intptr_t hash = 0;
-      for (size_t i = 0; i < strlen(key); i++) {
-        hash = CombineHashes(hash, key[i]);
-      }
-      return FinalizeHash(hash, kBitsPerWord - 1);
-    }
-    static bool IsKeyEqual(Pair kv, Key key) {
-      return kv.key == key || strcmp(kv.key, key) == 0;
-    }
-  };
-
-  using ExtraInfoKeyValueTrait = CStringPointerKeyValueTrait<SExpression*>;
-  using ExtraInfoHashMap = DirectChainedHashMap<ExtraInfoKeyValueTrait>;
+  using ExtraInfoHashMap = CStringMap<SExpression*>;
 
   void Add(SExpression* sexp);
   void AddExtra(const char* label, SExpression* value);
@@ -174,7 +145,7 @@
     return extra_info_.GetIterator();
   }
   bool ExtraHasKey(const char* cstr) const { return extra_info_.HasKey(cstr); }
-  ExtraInfoKeyValueTrait::Value ExtraLookupValue(const char* cstr) const {
+  SExpression* ExtraLookupValue(const char* cstr) const {
     return extra_info_.LookupValue(cstr);
   }
 
@@ -292,7 +263,7 @@
   SExpression* TokenToSExpression(Token* token);
   Token* GetNextToken();
   void Reset();
-  void StoreError(intptr_t pos, const char* format, ...);
+  void StoreError(intptr_t pos, const char* format, ...) PRINTF_ATTRIBUTE(3, 4);
 
   static bool IsSymbolContinue(char c);
 
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index bb0c918..d928420 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -46,6 +46,55 @@
   DirectChainedHashMap<PointerKeyValueTrait<const Slot> > fields_;
 };
 
+#define NATIVE_SLOT_NAME(C, F, id, M) Kind::k##C##_##F
+#define NATIVE_TO_STR(C, F, id, M) #C "_" #F
+
+const char* Slot::KindToCString(Kind k) {
+  switch (k) {
+#define NATIVE_CASE(C, F, id, M)                                               \
+  case NATIVE_SLOT_NAME(C, F, id, M):                                          \
+    return NATIVE_TO_STR(C, F, id, M);
+    NATIVE_SLOTS_LIST(NATIVE_CASE)
+#undef NATIVE_CASE
+    case Kind::kTypeArguments:
+      return "TypeArguments";
+    case Kind::kCapturedVariable:
+      return "CapturedVariable";
+    case Kind::kDartField:
+      return "DartField";
+    default:
+      UNREACHABLE();
+      return nullptr;
+  }
+}
+
+bool Slot::KindFromCString(const char* str, Kind* out) {
+  ASSERT(str != nullptr && out != nullptr);
+#define NATIVE_CASE(C, F, id, M)                                               \
+  if (strcmp(str, NATIVE_TO_STR(C, F, id, M)) == 0) {                          \
+    *out = NATIVE_SLOT_NAME(C, F, id, M);                                      \
+    return true;                                                               \
+  }
+  NATIVE_SLOTS_LIST(NATIVE_CASE)
+#undef NATIVE_CASE
+  if (strcmp(str, "TypeArguments") == 0) {
+    *out = Kind::kTypeArguments;
+    return true;
+  }
+  if (strcmp(str, "CapturedVariable") == 0) {
+    *out = Kind::kCapturedVariable;
+    return true;
+  }
+  if (strcmp(str, "DartField") == 0) {
+    *out = Kind::kDartField;
+    return true;
+  }
+  return false;
+}
+
+#undef NATIVE_TO_STR
+#undef NATIVE_SLOT_NAME
+
 const Slot& Slot::GetNativeSlot(Kind kind) {
   // There is a fixed statically known number of native slots so we cache
   // them statically.
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 46141a9..361532b 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -102,6 +102,9 @@
   };
   // clang-format on
 
+  static const char* KindToCString(Kind k);
+  static bool KindFromCString(const char* str, Kind* k);
+
   // Returns a slot that represents length field for the given [array_cid].
   static const Slot& GetLengthFieldForArrayCid(intptr_t array_cid);
 
@@ -144,7 +147,7 @@
   bool is_immutable() const { return IsImmutableBit::decode(flags_); }
 
   intptr_t nullable_cid() const { return cid_; }
-  intptr_t is_nullable() const { return IsNullableBit::decode(flags_); }
+  bool is_nullable() const { return IsNullableBit::decode(flags_); }
 
   // Returns true if properties of this slot were based on the guarded state
   // of the corresponding Dart field.
@@ -171,6 +174,8 @@
   bool IsIdentical(const Slot& other) const { return this == &other; }
 
  private:
+  friend class FlowGraphDeserializer;  // For GetNativeSlot.
+
   Slot(Kind kind,
        int8_t bits,
        int16_t cid,
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 7043c36..bbf2391 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -662,7 +662,7 @@
 }
 
 CompileType CompileType::Int32() {
-#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
+#if defined(TARGET_ARCH_IS_64_BIT)
   return FromCid(kSmiCid);
 #else
   return Int();
@@ -1066,12 +1066,6 @@
     return CompileType(CompileType::kNonNullable, cid, &type);
   }
 
-  if (function.HasBytecode() &&
-      graph_entry->parsed_function().scope() == nullptr) {
-    // TODO(alexmarkov): Consider adding scope.
-    return CompileType::Dynamic();
-  }
-
   const bool is_unchecked_entry_param =
       graph_entry->unchecked_entry() == block_;
 
@@ -1079,8 +1073,13 @@
     LocalScope* scope = graph_entry->parsed_function().scope();
     // Note: in catch-blocks we have ParameterInstr for each local variable
     // not only for normal parameters.
-    if (index() < scope->num_variables()) {
-      const LocalVariable* param = scope->VariableAt(index());
+    const LocalVariable* param = nullptr;
+    if (scope != nullptr && (index() < scope->num_variables())) {
+      param = scope->VariableAt(index());
+    } else if (index() < function.NumParameters()) {
+      param = graph_entry->parsed_function().RawParameterVariable(index());
+    }
+    if (param != nullptr) {
       CompileType* inferred_type = NULL;
       if (!block_->IsCatchBlockEntry()) {
         inferred_type = param->parameter_type();
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 0626731..5e93802 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -40,131 +40,19 @@
   return (cid == kSmiCid) || (cid == kDoubleCid);
 }
 
-static bool ClassIdIsOneOf(intptr_t class_id,
-                           const GrowableArray<intptr_t>& class_ids) {
-  for (intptr_t i = 0; i < class_ids.length(); i++) {
-    ASSERT(class_ids[i] != kIllegalCid);
-    if (class_ids[i] == class_id) {
-      return true;
-    }
-  }
-  return false;
-}
-
-// Returns true if ICData tests two arguments and all ICData cids are in the
-// required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
-static bool ICDataHasOnlyReceiverArgumentClassIds(
-    const ICData& ic_data,
-    const GrowableArray<intptr_t>& receiver_class_ids,
-    const GrowableArray<intptr_t>& argument_class_ids) {
-  if (ic_data.NumArgsTested() != 2) {
-    return false;
-  }
-  const intptr_t len = ic_data.NumberOfChecks();
-  GrowableArray<intptr_t> class_ids;
-  for (intptr_t i = 0; i < len; i++) {
-    if (ic_data.IsUsedAt(i)) {
-      ic_data.GetClassIdsAt(i, &class_ids);
-      ASSERT(class_ids.length() == 2);
-      if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
-          !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
-                                              intptr_t receiver_class_id,
-                                              intptr_t argument_class_id) {
-  if (ic_data.NumArgsTested() != 2) {
-    return false;
-  }
-  const intptr_t len = ic_data.NumberOfChecks();
-  for (intptr_t i = 0; i < len; i++) {
-    if (ic_data.IsUsedAt(i)) {
-      GrowableArray<intptr_t> class_ids;
-      ic_data.GetClassIdsAt(i, &class_ids);
-      ASSERT(class_ids.length() == 2);
-      if ((class_ids[0] == receiver_class_id) &&
-          (class_ids[1] == argument_class_id)) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-static bool HasOnlyOneSmi(const ICData& ic_data) {
-  return (ic_data.NumberOfUsedChecks() == 1) &&
-         ic_data.HasReceiverClassId(kSmiCid);
-}
-
-static bool HasOnlySmiOrMint(const ICData& ic_data) {
-  if (ic_data.NumberOfUsedChecks() == 1) {
-    return ic_data.HasReceiverClassId(kSmiCid) ||
-           ic_data.HasReceiverClassId(kMintCid);
-  }
-  return (ic_data.NumberOfUsedChecks() == 2) &&
-         ic_data.HasReceiverClassId(kSmiCid) &&
-         ic_data.HasReceiverClassId(kMintCid);
-}
-
-bool CallSpecializer::HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
-  if (ic_data.NumberOfUsedChecks() != 1) {
-    return false;
-  }
-  GrowableArray<intptr_t> first;
-  GrowableArray<intptr_t> second;
-  ic_data.GetUsedCidsForTwoArgs(&first, &second);
-  return (first[0] == cid) && (second[0] == cid);
-}
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Mint and Smi for the receiver and argument classes.
-static bool HasTwoMintOrSmi(const ICData& ic_data) {
-  GrowableArray<intptr_t> first;
-  GrowableArray<intptr_t> second;
-  ic_data.GetUsedCidsForTwoArgs(&first, &second);
-  for (intptr_t i = 0; i < first.length(); i++) {
-    if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
-      return false;
-    }
-    if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Double and Smi for the receiver and argument classes.
-static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
-  GrowableArray<intptr_t> class_ids(2);
-  class_ids.Add(kSmiCid);
-  class_ids.Add(kDoubleCid);
-  return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
-}
-
-static bool HasOnlyOneDouble(const ICData& ic_data) {
-  return (ic_data.NumberOfUsedChecks() == 1) &&
-         ic_data.HasReceiverClassId(kDoubleCid);
-}
-
-static bool ShouldSpecializeForDouble(const ICData& ic_data) {
+static bool ShouldSpecializeForDouble(const BinaryFeedback& binary_feedback) {
   // Don't specialize for double if we can't unbox them.
   if (!CanUnboxDouble()) {
     return false;
   }
 
   // Unboxed double operation can't handle case of two smis.
-  if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+  if (binary_feedback.IncludesOperands(kSmiCid)) {
     return false;
   }
 
-  // Check that it have seen only smis and doubles.
-  return HasTwoDoubleOrSmi(ic_data);
+  // Check that the call site has seen only smis and doubles.
+  return binary_feedback.OperandsAreSmiOrDouble();
 }
 
 // Optimize instance calls using ICData.
@@ -208,7 +96,8 @@
 
 bool CallSpecializer::TryCreateICData(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
-  if (call->ic_data()->NumberOfUsedChecks() > 0) {
+
+  if (call->Targets().length() > 0) {
     // This occurs when an instance call has too many checks, will be converted
     // to megamorphic call.
     return false;
@@ -272,17 +161,14 @@
       return false;
     }
 
-    // Create new ICData, do not modify the one attached to the instruction
-    // since it is attached to the assembly instruction itself.
-    const ICData& ic_data = ICData::ZoneHandle(
-        Z, ICData::NewFrom(*call->ic_data(), class_ids.length()));
-    if (class_ids.length() > 1) {
-      ic_data.AddCheck(class_ids, function);
-    } else {
-      ASSERT(class_ids.length() == 1);
-      ic_data.AddReceiverCheck(class_ids[0], function);
+    // Update the CallTargets attached to the instruction with our speculative
+    // target. The next round of CallSpecializer::VisitInstanceCall will make
+    // use of this.
+    call->SetTargets(CallTargets::CreateMonomorphic(Z, class_ids[0], function));
+    if (class_ids.length() == 2) {
+      call->SetBinaryFeedback(
+          BinaryFeedback::CreateMonomorphic(Z, class_ids[0], class_ids[1]));
     }
-    call->set_ic_data(&ic_data);
     return true;
   }
 
@@ -365,11 +251,11 @@
 }
 
 void CallSpecializer::AddChecksForArgNr(InstanceCallInstr* call,
-                                        Definition* instr,
+                                        Definition* argument,
                                         int argument_number) {
   const Cids* cids =
-      Cids::CreateAndExpand(Z, *call->ic_data(), argument_number);
-  AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call);
+      Cids::CreateForArgument(zone(), call->BinaryFeedback(), argument_number);
+  AddCheckClass(argument, *cids, call->deopt_id(), call->env(), call);
 }
 
 void CallSpecializer::AddCheckNull(Value* to_check,
@@ -390,30 +276,12 @@
   }
 }
 
-static bool ArgIsAlways(intptr_t cid,
-                        const ICData& ic_data,
-                        intptr_t arg_number) {
-  ASSERT(ic_data.NumArgsTested() > arg_number);
-  if (ic_data.NumberOfUsedChecks() == 0) {
-    return false;
+bool CallSpecializer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+  if (call->Targets().IsMonomorphic()) {
+    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
+        flow_graph_, current_iterator(), call, speculative_policy_);
   }
-  const intptr_t num_checks = ic_data.NumberOfChecks();
-  for (intptr_t i = 0; i < num_checks; i++) {
-    if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool CallSpecializer::TryReplaceWithIndexedOp(InstanceCallInstr* call,
-                                              const ICData* unary_checks) {
-  // Check for monomorphic IC data.
-  if (!unary_checks->NumberOfChecksIs(1)) {
-    return false;
-  }
-  return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-      flow_graph_, current_iterator(), call, speculative_policy_);
+  return false;
 }
 
 // Return true if d is a string of length one (a constant or result from
@@ -436,7 +304,7 @@
 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
 bool CallSpecializer::TryStringLengthOneEquality(InstanceCallInstr* call,
                                                  Token::Kind op_kind) {
-  ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
+  ASSERT(call->BinaryFeedback().OperandsAre(kOneByteStringCid));
   // Check that left and right are length one strings (either string constants
   // or results of string-from-char-code.
   Definition* left = call->ArgumentAt(0);
@@ -516,8 +384,7 @@
 
 bool CallSpecializer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
                                                Token::Kind op_kind) {
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.NumArgsTested() == 2);
+  const BinaryFeedback& binary_feedback = call->BinaryFeedback();
 
   ASSERT(call->type_args_len() == 0);
   ASSERT(call->ArgumentCount() == 2);
@@ -525,9 +392,9 @@
   Definition* const right = call->ArgumentAt(1);
 
   intptr_t cid = kIllegalCid;
-  if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
+  if (binary_feedback.OperandsAre(kOneByteStringCid)) {
     return TryStringLengthOneEquality(call, op_kind);
-  } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+  } else if (binary_feedback.OperandsAre(kSmiCid)) {
     InsertBefore(call,
                  new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
                                        call->token_pos()),
@@ -537,15 +404,15 @@
                                        call->token_pos()),
                  call->env(), FlowGraph::kEffect);
     cid = kSmiCid;
-  } else if (HasTwoMintOrSmi(ic_data) &&
+  } else if (binary_feedback.OperandsAreSmiOrMint() &&
              FlowGraphCompiler::SupportsUnboxedInt64()) {
     cid = kMintCid;
-  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+  } else if (binary_feedback.OperandsAreSmiOrDouble() && CanUnboxDouble()) {
     // Use double comparison.
     if (SmiFitsInDouble()) {
       cid = kDoubleCid;
     } else {
-      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+      if (binary_feedback.IncludesOperands(kSmiCid)) {
         // We cannot use double comparison on two smis. Need polymorphic
         // call.
         return false;
@@ -562,11 +429,7 @@
     // Check if ICDData contains checks with Smi/Null combinations. In that case
     // we can still emit the optimized Smi equality operation but need to add
     // checks for null or Smi.
-    GrowableArray<intptr_t> smi_or_null(2);
-    smi_or_null.Add(kSmiCid);
-    smi_or_null.Add(kNullCid);
-    if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null,
-                                              smi_or_null)) {
+    if (binary_feedback.OperandsAreSmiOrNull()) {
       AddChecksForArgNr(call, left, /* arg_number = */ 0);
       AddChecksForArgNr(call, right, /* arg_number = */ 1);
 
@@ -599,16 +462,15 @@
 
 bool CallSpecializer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
                                                  Token::Kind op_kind) {
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.NumArgsTested() == 2);
-
   ASSERT(call->type_args_len() == 0);
   ASSERT(call->ArgumentCount() == 2);
+
+  const BinaryFeedback& binary_feedback = call->BinaryFeedback();
   Definition* left = call->ArgumentAt(0);
   Definition* right = call->ArgumentAt(1);
 
   intptr_t cid = kIllegalCid;
-  if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+  if (binary_feedback.OperandsAre(kSmiCid)) {
     InsertBefore(call,
                  new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
                                        call->token_pos()),
@@ -618,15 +480,15 @@
                                        call->token_pos()),
                  call->env(), FlowGraph::kEffect);
     cid = kSmiCid;
-  } else if (HasTwoMintOrSmi(ic_data) &&
+  } else if (binary_feedback.OperandsAreSmiOrMint() &&
              FlowGraphCompiler::SupportsUnboxedInt64()) {
     cid = kMintCid;
-  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+  } else if (binary_feedback.OperandsAreSmiOrDouble() && CanUnboxDouble()) {
     // Use double comparison.
     if (SmiFitsInDouble()) {
       cid = kDoubleCid;
     } else {
-      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+      if (binary_feedback.IncludesOperands(kSmiCid)) {
         // We cannot use double comparison on two smis. Need polymorphic
         // call.
         return false;
@@ -654,31 +516,33 @@
                                              Token::Kind op_kind) {
   intptr_t operands_type = kIllegalCid;
   ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
+  const BinaryFeedback& binary_feedback = call->BinaryFeedback();
   switch (op_kind) {
     case Token::kADD:
     case Token::kSUB:
     case Token::kMUL:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (binary_feedback.OperandsAre(kSmiCid)) {
         // Don't generate smi code if the IC data is marked because
         // of an overflow.
-        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
-                            ? kMintCid
-                            : kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data) &&
+        operands_type =
+            call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)
+                ? kMintCid
+                : kSmiCid;
+      } else if (binary_feedback.OperandsAreSmiOrMint() &&
                  FlowGraphCompiler::SupportsUnboxedInt64()) {
         // Don't generate mint code if the IC data is marked because of an
         // overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) return false;
+        if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op))
+          return false;
         operands_type = kMintCid;
-      } else if (ShouldSpecializeForDouble(ic_data)) {
+      } else if (ShouldSpecializeForDouble(binary_feedback)) {
         operands_type = kDoubleCid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+      } else if (binary_feedback.OperandsAre(kFloat32x4Cid)) {
         operands_type = kFloat32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+      } else if (binary_feedback.OperandsAre(kInt32x4Cid)) {
         ASSERT(op_kind != Token::kMUL);  // Int32x4 doesn't have a multiply op.
         operands_type = kInt32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+      } else if (binary_feedback.OperandsAre(kFloat64x2Cid)) {
         operands_type = kFloat64x2Cid;
       } else {
         return false;
@@ -686,12 +550,12 @@
       break;
     case Token::kDIV:
       if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
-      if (ShouldSpecializeForDouble(ic_data) ||
-          HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (ShouldSpecializeForDouble(binary_feedback) ||
+          binary_feedback.OperandsAre(kSmiCid)) {
         operands_type = kDoubleCid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+      } else if (binary_feedback.OperandsAre(kFloat32x4Cid)) {
         operands_type = kFloat32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+      } else if (binary_feedback.OperandsAre(kFloat64x2Cid)) {
         operands_type = kFloat64x2Cid;
       } else {
         return false;
@@ -700,11 +564,11 @@
     case Token::kBIT_AND:
     case Token::kBIT_OR:
     case Token::kBIT_XOR:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (binary_feedback.OperandsAre(kSmiCid)) {
         operands_type = kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data)) {
+      } else if (binary_feedback.OperandsAreSmiOrMint()) {
         operands_type = kMintCid;
-      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+      } else if (binary_feedback.OperandsAre(kInt32x4Cid)) {
         operands_type = kInt32x4Cid;
       } else {
         return false;
@@ -712,22 +576,22 @@
       break;
     case Token::kSHR:
     case Token::kSHL:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (binary_feedback.OperandsAre(kSmiCid)) {
         // Left shift may overflow from smi into mint or big ints.
         // Don't generate smi code if the IC data is marked because
         // of an overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
+        if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
           return false;
         }
-        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
-                            ? kMintCid
-                            : kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data) &&
-                 HasOnlyOneSmi(ICData::Handle(
-                     Z, ic_data.AsUnaryClassChecksForArgNr(1)))) {
+        operands_type =
+            call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)
+                ? kMintCid
+                : kSmiCid;
+      } else if (binary_feedback.OperandsAreSmiOrMint() &&
+                 binary_feedback.ArgumentIs(kSmiCid)) {
         // Don't generate mint code if the IC data is marked because of an
         // overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
+        if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
           return false;
         }
         // Check for smi/mint << smi or smi/mint >> smi.
@@ -739,8 +603,8 @@
     case Token::kMOD:
     case Token::kTRUNCDIV:
       if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
+      if (binary_feedback.OperandsAre(kSmiCid)) {
+        if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
           return false;
         }
         operands_type = kSmiCid;
@@ -844,7 +708,7 @@
   ASSERT(call->ArgumentCount() == 1);
   Definition* input = call->ArgumentAt(0);
   Definition* unary_op = NULL;
-  if (HasOnlyOneSmi(*call->ic_data())) {
+  if (call->Targets().ReceiverIs(kSmiCid)) {
     InsertBefore(call,
                  new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(),
                                        call->token_pos()),
@@ -852,11 +716,11 @@
     unary_op = new (Z)
         UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
   } else if ((op_kind == Token::kBIT_NOT) &&
-             HasOnlySmiOrMint(*call->ic_data()) &&
+             call->Targets().ReceiverIsSmiOrMint() &&
              FlowGraphCompiler::SupportsUnboxedInt64()) {
     unary_op = new (Z)
         UnaryInt64OpInstr(op_kind, new (Z) Value(input), call->deopt_id());
-  } else if (HasOnlyOneDouble(*call->ic_data()) &&
+  } else if (call->Targets().ReceiverIs(kDoubleCid) &&
              (op_kind == Token::kNEGATE) && CanUnboxDouble()) {
     AddReceiverCheck(call);
     unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input),
@@ -869,33 +733,16 @@
   return true;
 }
 
-// Lookup field with the given name in the given class.
-RawField* CallSpecializer::GetField(intptr_t class_id,
-                                    const String& field_name) {
-  Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
-  Field& field = Field::Handle(Z);
-  while (!cls.IsNull()) {
-    field = cls.LookupInstanceField(field_name);
-    if (!field.IsNull()) {
-      return should_clone_fields_ ? field.CloneFromOriginal() : field.raw();
-    }
-    cls = cls.SuperClass();
-  }
-  return Field::null();
-}
-
 bool CallSpecializer::TryInlineImplicitInstanceGetter(InstanceCallInstr* call) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.HasOneTarget());
-  GrowableArray<intptr_t> class_ids;
-  ic_data.GetClassIdsAt(0, &class_ids);
-  ASSERT(class_ids.length() == 1);
+  const CallTargets& targets = call->Targets();
+  ASSERT(targets.HasSingleTarget());
+
   // Inline implicit instance getter.
-  const String& field_name =
-      String::Handle(Z, Field::NameFromGetter(call->function_name()));
-  const Field& field = Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
+  Field& field = Field::ZoneHandle(Z, targets.FirstTarget().accessor_field());
   ASSERT(!field.IsNull());
+  if (should_clone_fields_) {
+    field = field.CloneFromOriginal();
+  }
 
   switch (
       flow_graph()->CheckForInstanceCall(call, RawFunction::kImplicitGetter)) {
@@ -935,35 +782,23 @@
   }
 }
 
-bool CallSpecializer::TryInlineInstanceSetter(InstanceCallInstr* instr,
-                                              const ICData& unary_ic_data) {
-  ASSERT(!unary_ic_data.NumberOfChecksIs(0) &&
-         (unary_ic_data.NumArgsTested() == 1));
-  ASSERT(instr->HasICData());
-  if (unary_ic_data.NumberOfChecksIs(0)) {
-    // No type feedback collected.
-    return false;
-  }
-  if (!unary_ic_data.HasOneTarget()) {
+bool CallSpecializer::TryInlineInstanceSetter(InstanceCallInstr* instr) {
+  const CallTargets& targets = instr->Targets();
+  if (!targets.HasSingleTarget()) {
     // Polymorphic sites are inlined like normal method calls by conventional
     // inlining.
     return false;
   }
-  Function& target = Function::Handle(Z);
-  intptr_t class_id;
-  unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
+  const Function& target = targets.FirstTarget();
   if (target.kind() != RawFunction::kImplicitSetter) {
     // Non-implicit setter are inlined like normal method calls.
     return false;
   }
-  // Inline implicit instance setter.
-  String& field_name = String::Handle(Z, instr->function_name().raw());
-  if (Function::IsDynamicInvocationForwarderName(field_name)) {
-    field_name = Function::DemangleDynamicInvocationForwarderName(field_name);
-  }
-  field_name = Field::NameFromSetter(field_name);
-  const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name));
+  Field& field = Field::ZoneHandle(Z, target.accessor_field());
   ASSERT(!field.IsNull());
+  if (should_clone_fields_) {
+    field = field.CloneFromOriginal();
+  }
 
   switch (
       flow_graph()->CheckForInstanceCall(instr, RawFunction::kImplicitSetter)) {
@@ -984,10 +819,10 @@
   // True if we can use unchecked entry into the setter.
   bool is_unchecked_call = false;
   if (!FLAG_precompiled_mode) {
-    if (unary_ic_data.NumberOfChecks() == 1 &&
-        unary_ic_data.GetExactnessAt(0).IsExact()) {
-      if (unary_ic_data.GetExactnessAt(0).IsTriviallyExact()) {
-        flow_graph()->AddExactnessGuard(instr, unary_ic_data.GetCidAt(0));
+    if (targets.IsMonomorphic() && targets.MonomorphicExactness().IsExact()) {
+      if (targets.MonomorphicExactness().IsTriviallyExact()) {
+        flow_graph()->AddExactnessGuard(instr,
+                                        targets.MonomorphicReceiverCid());
       }
       is_unchecked_call = true;
     }
@@ -1109,20 +944,13 @@
 
 // Only unique implicit instance getters can be currently handled.
 bool CallSpecializer::TryInlineInstanceGetter(InstanceCallInstr* call) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  if (ic_data.NumberOfUsedChecks() == 0) {
-    // No type feedback collected.
-    return false;
-  }
-
-  if (!ic_data.HasOneTarget()) {
+  const CallTargets& targets = call->Targets();
+  if (!targets.HasSingleTarget()) {
     // Polymorphic sites are inlined like normal methods by conventional
     // inlining in FlowGraphInliner.
     return false;
   }
-
-  const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
+  const Function& target = targets.FirstTarget();
   if (target.kind() != RawFunction::kImplicitGetter) {
     // Non-implicit getters are inlined like normal methods by conventional
     // inlining in FlowGraphInliner.
@@ -1148,28 +976,26 @@
 
 // Inline only simple, frequently called core library methods.
 bool CallSpecializer::TryInlineInstanceMethod(InstanceCallInstr* call) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  if (ic_data.NumberOfUsedChecks() != 1) {
+  const CallTargets& targets = call->Targets();
+  if (!targets.IsMonomorphic()) {
     // No type feedback collected or multiple receivers/targets found.
     return false;
   }
 
-  Function& target = Function::Handle(Z);
-  GrowableArray<intptr_t> class_ids;
-  ic_data.GetCheckAt(0, &class_ids, &target);
+  const Function& target = targets.FirstTarget();
+  intptr_t receiver_cid = targets.MonomorphicReceiverCid();
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(target);
 
   if (CanUnboxDouble() &&
       (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
-    if (class_ids[0] == kSmiCid) {
+    if (receiver_cid == kSmiCid) {
       AddReceiverCheck(call);
       ReplaceCall(call,
                   new (Z) SmiToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
                                            call->token_pos()));
       return true;
-    } else if ((class_ids[0] == kMintCid) && CanConvertInt64ToDouble()) {
+    } else if ((receiver_cid == kMintCid) && CanConvertInt64ToDouble()) {
       AddReceiverCheck(call);
       ReplaceCall(call,
                   new (Z) Int64ToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
@@ -1178,7 +1004,7 @@
     }
   }
 
-  if (class_ids[0] == kDoubleCid) {
+  if (receiver_cid == kDoubleCid) {
     if (!CanUnboxDouble()) {
       return false;
     }
@@ -1281,7 +1107,7 @@
             : Class::IsSubtypeOf(cls, Object::null_type_arguments(), type_class,
                                  Object::null_type_arguments(), Heap::kOld);
     results->Add(cls.id());
-    results->Add(is_subtype);
+    results->Add(static_cast<intptr_t>(is_subtype));
     if (prev.IsNull()) {
       prev = Bool::Get(is_subtype).raw();
     } else {
@@ -1480,22 +1306,20 @@
 
     MethodRecognizer::Kind recognized_kind =
         MethodRecognizer::RecognizeKind(call->function());
+    const CallTargets& targets = call->Targets();
+    const BinaryFeedback& binary_feedback = call->BinaryFeedback();
 
     switch (recognized_kind) {
       case MethodRecognizer::kMathMin:
       case MethodRecognizer::kMathMax: {
         // We can handle only monomorphic min/max call sites with both arguments
         // being either doubles or smis.
-        if (CanUnboxDouble() && call->HasICData() &&
-            call->ic_data()->NumberOfChecksIs(1) &&
+        if (CanUnboxDouble() && targets.IsMonomorphic() &&
             (call->FirstArgIndex() == 0)) {
-          const ICData& ic_data = *call->ic_data();
           intptr_t result_cid = kIllegalCid;
-          if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid,
-                                                kDoubleCid)) {
+          if (binary_feedback.IncludesOperands(kDoubleCid)) {
             result_cid = kDoubleCid;
-          } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid,
-                                                       kSmiCid)) {
+          } else if (binary_feedback.IncludesOperands(kSmiCid)) {
             result_cid = kSmiCid;
           }
           if (result_cid != kIllegalCid) {
@@ -1503,8 +1327,7 @@
                 recognized_kind, new (Z) Value(call->ArgumentAt(0)),
                 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(),
                 result_cid);
-            const Cids* cids =
-                Cids::CreateAndExpand(Z, ic_data, /* argument_number =*/0);
+            const Cids* cids = Cids::CreateMonomorphic(Z, result_cid);
             AddCheckClass(min_max->left()->definition(), *cids,
                           call->deopt_id(), call->env(), call);
             AddCheckClass(min_max->right()->definition(), *cids,
@@ -1516,17 +1339,16 @@
         break;
       }
       case MethodRecognizer::kDoubleFromInteger: {
-        if (call->HasICData() && call->ic_data()->NumberOfChecksIs(1) &&
+        if (call->HasICData() && targets.IsMonomorphic() &&
             (call->FirstArgIndex() == 0)) {
-          const ICData& ic_data = *call->ic_data();
           if (CanUnboxDouble()) {
-            if (ArgIsAlways(kSmiCid, ic_data, 1)) {
+            if (binary_feedback.ArgumentIs(kSmiCid)) {
               Definition* arg = call->ArgumentAt(1);
               AddCheckSmi(arg, call->deopt_id(), call->env(), call);
               ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg),
                                                          call->token_pos()));
               return;
-            } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
+            } else if (binary_feedback.ArgumentIs(kMintCid) &&
                        CanConvertInt64ToDouble()) {
               Definition* arg = call->ArgumentAt(1);
               ReplaceCall(call, new (Z) Int64ToDoubleInstr(new (Z) Value(arg),
@@ -1569,7 +1391,7 @@
                        bool result) {
   if (!CidTestResultsContains(*results, test_cid)) {
     results->Add(test_cid);
-    results->Add(result);
+    results->Add(static_cast<intptr_t>(result));
   }
 }
 
@@ -1605,7 +1427,7 @@
       (*results)[i] = (*results)[i - 2];
     }
     (*results)[0] = kSmiCid;
-    (*results)[1] = smi_is_subtype;
+    (*results)[1] = static_cast<intptr_t>(smi_is_subtype);
   }
 
   ASSERT(type.IsInstantiated());
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index 2b1e4ee..78e442f 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -67,8 +67,7 @@
   Zone* zone() const { return flow_graph_->zone(); }
   const Function& function() const { return flow_graph_->function(); }
 
-  bool TryReplaceWithIndexedOp(InstanceCallInstr* call,
-                               const ICData* unary_checks);
+  bool TryReplaceWithIndexedOp(InstanceCallInstr* call);
 
   bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
   bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
@@ -77,8 +76,7 @@
   bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
 
   bool TryInlineInstanceGetter(InstanceCallInstr* call);
-  bool TryInlineInstanceSetter(InstanceCallInstr* call,
-                               const ICData& unary_ic_data);
+  bool TryInlineInstanceSetter(InstanceCallInstr* call);
 
   bool TryInlineInstanceMethod(InstanceCallInstr* call);
   void ReplaceWithInstanceOf(InstanceCallInstr* instr);
@@ -93,8 +91,8 @@
 
   // Add a class check for the call's first argument (receiver).
   void AddReceiverCheck(InstanceCallInstr* call) {
-    AddChecksForArgNr(call, call->Receiver()->definition(),
-                      /* argument_number = */ 0);
+    AddCheckClass(call->Receiver()->definition(), call->Targets(),
+                  call->deopt_id(), call->env(), call);
   }
 
   // Insert a null check if needed.
@@ -107,8 +105,6 @@
   // Attempt to build ICData for call using propagated class-ids.
   virtual bool TryCreateICData(InstanceCallInstr* call);
 
-  static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid);
-
   virtual bool TryReplaceInstanceOfWithRangeCheck(InstanceCallInstr* call,
                                                   const AbstractType& type);
 
@@ -143,7 +139,7 @@
   // call, using the call's IC data to determine the check, and the call's
   // deopt ID and deoptimization environment if the check fails.
   void AddChecksForArgNr(InstanceCallInstr* call,
-                         Definition* instr,
+                         Definition* argument,
                          int argument_number);
 
   bool InlineSimdBinaryOp(InstanceCallInstr* call,
@@ -164,8 +160,6 @@
 
   bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
 
-  RawField* GetField(intptr_t class_id, const String& field_name);
-
   void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
 
   // Tries to add cid tests to 'results' so that no deoptimization is
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 6aba24a..110498d 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -10,6 +10,7 @@
 #include "vm/compiler/backend/branch_optimizer.h"
 #include "vm/compiler/backend/constant_propagator.h"
 #include "vm/compiler/backend/flow_graph_checker.h"
+#include "vm/compiler/backend/il_deserializer.h"
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/il_serializer.h"
 #include "vm/compiler/backend/inliner.h"
@@ -55,6 +56,14 @@
                       "List of comma separated compilation passes flags. "
                       "Use -Name to disable a pass, Name to print IL after it. "
                       "Do --compiler-passes=help for more information.");
+DEFINE_FLAG(bool,
+            early_round_trip_serialization,
+            false,
+            "Perform early round trip serialization compiler pass.");
+DEFINE_FLAG(bool,
+            late_round_trip_serialization,
+            false,
+            "Perform late round trip serialization compiler pass.");
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 
@@ -227,9 +236,47 @@
   INVOKE_PASS(TryOptimizePatterns);
 }
 
-void CompilerPass::RunPipeline(PipelineMode mode,
-                               CompilerPassState* pass_state) {
+FlowGraph* CompilerPass::RunForceOptimizedPipeline(
+    PipelineMode mode,
+    CompilerPassState* pass_state) {
   INVOKE_PASS(ComputeSSA);
+  if (FLAG_early_round_trip_serialization) {
+    INVOKE_PASS(RoundTripSerialization);
+  }
+  INVOKE_PASS(TypePropagation);
+  INVOKE_PASS(Canonicalize);
+  INVOKE_PASS(BranchSimplify);
+  INVOKE_PASS(IfConvert);
+  INVOKE_PASS(ConstantPropagation);
+  INVOKE_PASS(TypePropagation);
+  INVOKE_PASS(WidenSmiToInt32);
+  INVOKE_PASS(SelectRepresentations);
+  INVOKE_PASS(TypePropagation);
+  INVOKE_PASS(TryCatchOptimization);
+  INVOKE_PASS(EliminateEnvironments);
+  INVOKE_PASS(EliminateDeadPhis);
+  INVOKE_PASS(Canonicalize);
+  INVOKE_PASS(WriteBarrierElimination);
+  INVOKE_PASS(FinalizeGraph);
+#if defined(DART_PRECOMPILER)
+  if (mode == kAOT) {
+    INVOKE_PASS(SerializeGraph);
+  }
+#endif
+  if (FLAG_late_round_trip_serialization) {
+    INVOKE_PASS(RoundTripSerialization);
+  }
+  INVOKE_PASS(AllocateRegisters);
+  INVOKE_PASS(ReorderBlocks);
+  return pass_state->flow_graph;
+}
+
+FlowGraph* CompilerPass::RunPipeline(PipelineMode mode,
+                                     CompilerPassState* pass_state) {
+  INVOKE_PASS(ComputeSSA);
+  if (FLAG_early_round_trip_serialization) {
+    INVOKE_PASS(RoundTripSerialization);
+  }
 #if defined(DART_PRECOMPILER)
   if (mode == kAOT) {
     INVOKE_PASS(ApplyClassIds);
@@ -296,16 +343,21 @@
     INVOKE_PASS(SerializeGraph);
   }
 #endif
+  if (FLAG_late_round_trip_serialization) {
+    INVOKE_PASS(RoundTripSerialization);
+  }
   INVOKE_PASS(AllocateRegisters);
   INVOKE_PASS(ReorderBlocks);
+  return pass_state->flow_graph;
 }
 
-void CompilerPass::RunPipelineWithPasses(
+FlowGraph* CompilerPass::RunPipelineWithPasses(
     CompilerPassState* state,
     std::initializer_list<CompilerPass::Id> passes) {
   for (auto pass_id : passes) {
     passes_[pass_id]->Run(state);
   }
+  return state->flow_graph;
 }
 
 COMPILER_PASS(ComputeSSA, {
@@ -519,6 +571,11 @@
 });
 #endif
 
+COMPILER_PASS(RoundTripSerialization, {
+  FlowGraphDeserializer::RoundTripSerialization(state);
+  ASSERT(state->flow_graph != nullptr);
+})
+
 }  // namespace dart
 
 #endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index b8475d1..2d9b6d0 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -40,6 +40,7 @@
   V(OptimizeTypedDataAccesses)                                                 \
   V(RangeAnalysis)                                                             \
   V(ReorderBlocks)                                                             \
+  V(RoundTripSerialization)                                                    \
   V(SelectRepresentations)                                                     \
   V(SerializeGraph)                                                            \
   V(SetOuterInliningId)                                                        \
@@ -76,7 +77,7 @@
   }
 
   Thread* const thread;
-  FlowGraph* const flow_graph;
+  FlowGraph* flow_graph;
   Precompiler* const precompiler;
   int inlining_depth;
   AllocationSinking* sinking;
@@ -146,12 +147,27 @@
 
   static void RunInliningPipeline(PipelineMode mode, CompilerPassState* state);
 
-  static void RunPipeline(PipelineMode mode, CompilerPassState* state);
-
-  static void RunPipelineWithPasses(
+  // RunPipeline(WithPasses) may have the side effect of changing the FlowGraph
+  // stored in the CompilerPassState. However, existing callers may depend on
+  // the old invariant that the FlowGraph stored in the CompilerPassState was
+  // always updated, never entirely replaced.
+  //
+  // To make sure callers are updated properly, these methods also return
+  // the final FlowGraph and we add a check that callers use this result.
+  DART_WARN_UNUSED_RESULT
+  static FlowGraph* RunPipeline(PipelineMode mode, CompilerPassState* state);
+  DART_WARN_UNUSED_RESULT
+  static FlowGraph* RunPipelineWithPasses(
       CompilerPassState* state,
       std::initializer_list<CompilerPass::Id> passes);
 
+  // Pipeline which is used for "force-optimized" functions.
+  //
+  // Must not include speculative or inter-procedural optimizations.
+  DART_WARN_UNUSED_RESULT
+  static FlowGraph* RunForceOptimizedPipeline(PipelineMode mode,
+                                              CompilerPassState* state);
+
  protected:
   // This function executes the pass. If it returns true then
   // we will run Canonicalize on the graph and execute the pass
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 321a629..a722851 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -63,6 +63,8 @@
   "backend/il_arm.cc",
   "backend/il_arm64.cc",
   "backend/il_dbc.cc",
+  "backend/il_deserializer.cc",
+  "backend/il_deserializer.h",
   "backend/il_ia32.cc",
   "backend/il_printer.cc",
   "backend/il_printer.h",
diff --git a/runtime/vm/compiler/compiler_state.h b/runtime/vm/compiler/compiler_state.h
index 76326b2..be14d0b 100644
--- a/runtime/vm/compiler/compiler_state.h
+++ b/runtime/vm/compiler/compiler_state.h
@@ -115,15 +115,6 @@
   // TODO(vegorov): disambiguate slots for different context IDs.
   LocalVariable* GetDummyCapturedVariable(intptr_t context_id, intptr_t index);
 
-  ZoneGrowableArray<const MegamorphicCache*>& cloned_megamorphic_caches() {
-    if (cloned_megamorphic_caches_ == nullptr) {
-      Zone* Z = Thread::Current()->zone();
-      cloned_megamorphic_caches_ =
-          new (Z) ZoneGrowableArray<const MegamorphicCache*>(Z, 12);
-    }
-    return *cloned_megamorphic_caches_;
-  }
-
  private:
   CHA cha_;
   intptr_t deopt_id_ = 0;
@@ -136,9 +127,6 @@
   ZoneGrowableArray<ZoneGrowableArray<const Slot*>*>* dummy_slots_ = nullptr;
   ZoneGrowableArray<LocalVariable*>* dummy_captured_vars_ = nullptr;
 
-  ZoneGrowableArray<const MegamorphicCache*>* cloned_megamorphic_caches_ =
-      nullptr;
-
   CompilerState* previous_;
 };
 
diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc
index 5313922..3b3ce8c 100644
--- a/runtime/vm/compiler/ffi.cc
+++ b/runtime/vm/compiler/ffi.cc
@@ -210,6 +210,58 @@
 
 #if !defined(TARGET_ARCH_DBC)
 
+RawFunction* NativeCallbackFunction(const Function& c_signature,
+                                    const Function& dart_target,
+                                    const Instance& exceptional_return) {
+  Thread* const thread = Thread::Current();
+  const int32_t callback_id = thread->AllocateFfiCallbackId();
+
+  // Create a new Function named '<target>_FfiCallback' and stick it in the
+  // 'dart:ffi' library. Note that these functions will never be invoked by
+  // Dart, so they have may have duplicate names.
+  Zone* const zone = thread->zone();
+  const auto& name = String::Handle(
+      zone, Symbols::FromConcat(thread, Symbols::FfiCallback(),
+                                String::Handle(zone, dart_target.name())));
+  const Library& lib = Library::Handle(zone, Library::FfiLibrary());
+  const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
+  const Function& function =
+      Function::Handle(zone, Function::New(name, RawFunction::kFfiTrampoline,
+                                           /*is_static=*/true,
+                                           /*is_const=*/false,
+                                           /*is_abstract=*/false,
+                                           /*is_external=*/false,
+                                           /*is_native=*/false, owner_class,
+                                           TokenPosition::kNoSource));
+  function.set_is_debuggable(false);
+
+  // Set callback-specific fields which the flow-graph builder needs to generate
+  // the body.
+  function.SetFfiCSignature(c_signature);
+  function.SetFfiCallbackId(callback_id);
+  function.SetFfiCallbackTarget(dart_target);
+
+  // We need to load the exceptional return value as a constant in the generated
+  // function. Even though the FE ensures that it is a constant, it could still
+  // be a literal allocated in new space. We need to copy it into old space in
+  // that case.
+  //
+  // Exceptional return values currently cannot be pointers because we don't
+  // have constant pointers.
+  //
+  // TODO(36730): We'll need to extend this when we support passing/returning
+  // structs by value.
+  ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber());
+  if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
+    function.SetFfiCallbackExceptionalReturn(Instance::Handle(
+        zone, exceptional_return.CopyShallowToOldSpace(thread)));
+  } else {
+    function.SetFfiCallbackExceptionalReturn(exceptional_return);
+  }
+
+  return function.raw();
+}
+
 ZoneGrowableArray<Representation>* ArgumentRepresentations(
     const Function& signature) {
   return ArgumentRepresentationsBase<CallingConventions>(signature);
@@ -650,27 +702,6 @@
 
 #endif  // defined(TARGET_ARCH_DBC)
 
-bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func) {
-  Object& asFunctionInternal =
-      Object::Handle(zone, isolate->object_store()->ffi_as_function_internal());
-  if (asFunctionInternal.raw() == Object::null()) {
-    // Cache the reference.
-    const Library& ffi =
-        Library::Handle(zone, isolate->object_store()->ffi_library());
-    asFunctionInternal =
-        ffi.LookupFunctionAllowPrivate(Symbols::AsFunctionInternal());
-    // Cannot assert that 'asFunctionInternal' is found because it may have been
-    // tree-shaken.
-    if (asFunctionInternal.IsNull()) {
-      // Set the entry in the object store to a sentinel so we don't try to look
-      // it up again.
-      asFunctionInternal = Object::sentinel().raw();
-    }
-    isolate->object_store()->set_ffi_as_function_internal(asFunctionInternal);
-  }
-  return func.raw() == asFunctionInternal.raw();
-}
-
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
 }  // namespace ffi
diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h
index 5c743d4..7922a80 100644
--- a/runtime/vm/compiler/ffi.h
+++ b/runtime/vm/compiler/ffi.h
@@ -56,6 +56,10 @@
 
 #if !defined(TARGET_ARCH_DBC)
 
+RawFunction* NativeCallbackFunction(const Function& c_signature,
+                                    const Function& dart_target,
+                                    const Instance& exceptional_return);
+
 // Unboxed representations of the arguments to a C signature function.
 ZoneGrowableArray<Representation>* ArgumentRepresentations(
     const Function& signature);
@@ -145,11 +149,8 @@
   intptr_t argument_slots_used_ = 0;
   intptr_t argument_slots_required_ = 0;
 };
-
 #endif  // defined(TARGET_ARCH_DBC)
 
-bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func);
-
 }  // namespace ffi
 
 }  // namespace compiler
diff --git a/runtime/vm/compiler/frontend/bytecode_fingerprints.cc b/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
index aa3e4b7..8a42a1e 100644
--- a/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
@@ -173,15 +173,17 @@
 uint32_t BytecodeFingerprintHelper::CalculateFunctionFingerprint(
     const Function& function) {
   ASSERT(function.is_declared_in_bytecode());
+  const intptr_t kHashBits = 30;
+  uint32_t fp = 0;
+  fp = CombineHashes(fp, String::Handle(function.UserVisibleName()).Hash());
   if (function.is_abstract()) {
-    return 0;
+    return FinalizeHash(fp, kHashBits);
   }
   if (!function.HasBytecode()) {
     kernel::BytecodeReader::ReadFunctionBytecode(Thread::Current(), function);
   }
   const Bytecode& code = Bytecode::Handle(function.bytecode());
   const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
-  uint32_t fp = 0;
   const KBCInstr* const start =
       reinterpret_cast<const KBCInstr*>(code.instructions());
   for (const KBCInstr* instr = start; (instr - start) < code.Size();
@@ -200,7 +202,7 @@
     }
   }
 
-  return FinalizeHash(fp, 30);
+  return FinalizeHash(fp, kHashBits);
 }
 
 }  // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 4afe636..a330e14 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -234,6 +234,14 @@
       TokenPosition::kNoSource, TokenPosition::kNoSource, name, type);
   param_var->set_index(var_index);
 
+  if (!function().IsNonImplicitClosureFunction() &&
+      (function().is_static() ||
+       ((function().name() != Symbols::Call().raw()) &&
+        !parsed_function()->IsCovariantParameter(param_index) &&
+        !parsed_function()->IsGenericCovariantImplParameter(param_index)))) {
+    param_var->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
+  }
+
   if (var_index.value() <= 0) {
     local_vars_[-var_index.value()] = param_var;
   }
@@ -799,9 +807,14 @@
   const Function& target = Function::Cast(ConstantAt(DecodeOperandD()).value());
   const intptr_t argc = DecodeOperandF().value();
 
-  if (compiler::ffi::IsAsFunctionInternal(Z, isolate(), target)) {
+  const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
+  if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
     BuildFfiAsFunction();
     return;
+  } else if (FLAG_precompiled_mode &&
+             recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
+    BuildFfiNativeCallbackFunction();
+    return;
   }
 
   // Recognize identical() call.
@@ -818,7 +831,7 @@
   }
 
   if (!FLAG_causal_async_stacks &&
-      target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper) {
+      recognized_kind == MethodRecognizer::kAsyncStackTraceHelper) {
     ASSERT(argc == 1);
     // Drop the ignored parameter to _asyncStackTraceHelper(:async_op).
     code_ += B->Drop();
@@ -826,7 +839,7 @@
     return;
   }
 
-  if (target.recognized_kind() == MethodRecognizer::kStringBaseInterpolate) {
+  if (recognized_kind == MethodRecognizer::kStringBaseInterpolate) {
     ASSERT(argc == 1);
     code_ += B->StringInterpolate(position_);
     return;
@@ -1216,8 +1229,6 @@
     UNIMPLEMENTED();  // TODO(alexmarkov): interpreter
   }
 
-  BuildDebugStepCheck();
-
   LoadStackSlots(1);
   Operand cp_index = DecodeOperandD();
 
@@ -1569,8 +1580,6 @@
     UNIMPLEMENTED();  // TODO(alexmarkov): interpreter
   }
 
-  BuildDebugStepCheck();
-
   if (DecodeOperandA().value() == 0) {
     // throw
     LoadStackSlots(1);
@@ -1820,6 +1829,45 @@
   code_ += B->BuildFfiAsFunctionInternalCall(type_args);
 }
 
+// Builds graph for a call to 'dart:ffi::_nativeCallbackFunction'.
+// The call-site must look like this (guaranteed by the FE which inserts it):
+//
+//   _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
+//
+// Therefore the stack shall look like:
+//
+// <exceptional return value> => ensured (by FE) to be a constant
+// <target> => closure, ensured (by FE) to be a (non-partially-instantiated)
+//             static tearoff
+// <type args> => [NativeSignatureType]
+void BytecodeFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
+#if defined(TARGET_ARCH_DBC)
+  UNREACHABLE();
+#else
+  const TypeArguments& type_args =
+      TypeArguments::Cast(B->Peek(/*depth=*/2)->AsConstant()->value());
+  ASSERT(type_args.IsInstantiated() && type_args.Length() == 1);
+  const Function& native_sig = Function::Handle(
+      Z, Type::Cast(AbstractType::Handle(Z, type_args.TypeAt(0))).signature());
+
+  const Closure& target_closure =
+      Closure::Cast(B->Peek(/*depth=*/1)->AsConstant()->value());
+  ASSERT(!target_closure.IsNull());
+  Function& target = Function::Handle(Z, target_closure.function());
+  ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
+  target = target.parent_function();
+
+  const Instance& exceptional_return =
+      Instance::Cast(B->Peek(/*depth=*/0)->AsConstant()->value());
+
+  const Function& result =
+      Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
+                                  native_sig, target, exceptional_return));
+  code_ += B->Constant(result);
+  code_ += B->DropTempsPreserveTop(3);
+#endif
+}
+
 void BytecodeFlowGraphBuilder::BuildDebugStepCheck() {
 #if !defined(PRODUCT)
   if (build_debug_step_checks_) {
@@ -1965,9 +2013,9 @@
         Array::ZoneHandle(Z, handlers.GetHandledTypes(try_index));
 
     CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr(
-        TokenPosition::kNoSource, handler_info.is_generated,
+        TokenPosition::kNoSource, handler_info.is_generated != 0,
         B->AllocateBlockId(), handler_info.outer_try_index, graph_entry,
-        handler_types, try_index, handler_info.needs_stacktrace,
+        handler_types, try_index, handler_info.needs_stacktrace != 0,
         B->GetNextDeoptId(), nullptr, nullptr, exception_var_, stacktrace_var_);
     graph_entry->AddCatchEntry(entry);
 
@@ -2026,34 +2074,62 @@
   }
 }
 
-#if !defined(PRODUCT)
-intptr_t BytecodeFlowGraphBuilder::UpdateContextLevel(const Bytecode& bytecode,
-                                                      intptr_t pc) {
-  ASSERT(B->is_recording_context_levels());
-
-  kernel::BytecodeLocalVariablesIterator iter(Z, bytecode);
-  intptr_t context_level = 0;
-  intptr_t next_pc = bytecode_length_;
-  while (iter.MoveNext()) {
-    if (iter.IsScope()) {
-      if (iter.StartPC() <= pc) {
-        if (pc < iter.EndPC()) {
-          // Found enclosing scope. Keep looking as we might find more
-          // scopes (the last one is the most specific).
-          context_level = iter.ContextLevel();
-          next_pc = iter.EndPC();
-        }
-      } else {
-        next_pc = Utils::Minimum(next_pc, iter.StartPC());
-        break;
-      }
+intptr_t BytecodeFlowGraphBuilder::UpdateScope(
+    BytecodeLocalVariablesIterator* iter,
+    intptr_t pc) {
+  // Leave scopes that have ended.
+  while ((current_scope_ != nullptr) && (current_scope_->end_pc_ <= pc)) {
+    for (LocalVariable* local : current_scope_->hidden_vars_) {
+      local_vars_[-local->index().value()] = local;
     }
+    current_scope_ = current_scope_->parent_;
   }
 
-  B->set_context_depth(context_level);
+  // Enter scopes that have started.
+  intptr_t next_pc = bytecode_length_;
+  while (!iter->IsDone()) {
+    if (iter->IsScope()) {
+      if (iter->StartPC() > pc) {
+        next_pc = iter->StartPC();
+        break;
+      }
+      if (iter->EndPC() > pc) {
+        // Push new scope and declare its variables.
+        current_scope_ = new (Z) BytecodeScope(
+            Z, iter->EndPC(), iter->ContextLevel(), current_scope_);
+        if (!seen_parameters_scope_) {
+          // Skip variables from the first scope as it may contain variables
+          // which were used in prologue (parameters, function type arguments).
+          // The already used variables should not be replaced with new ones.
+          seen_parameters_scope_ = true;
+          iter->MoveNext();
+          continue;
+        }
+        while (iter->MoveNext() && iter->IsVariableDeclaration()) {
+          const intptr_t index = iter->Index();
+          if (!iter->IsCaptured() && (index >= 0)) {
+            LocalVariable* local = new (Z) LocalVariable(
+                TokenPosition::kNoSource, TokenPosition::kNoSource,
+                String::ZoneHandle(Z, iter->Name()),
+                AbstractType::ZoneHandle(Z, iter->Type()));
+            local->set_index(VariableIndex(-index));
+            ASSERT(local_vars_[index]->index().value() == -index);
+            current_scope_->hidden_vars_.Add(local_vars_[index]);
+            local_vars_[index] = local;
+          }
+        }
+        continue;
+      }
+    }
+    iter->MoveNext();
+  }
+  if (current_scope_ != nullptr && next_pc > current_scope_->end_pc_) {
+    next_pc = current_scope_->end_pc_;
+  }
+  B->set_context_depth(
+      current_scope_ != nullptr ? current_scope_->context_level_ : 0);
   return next_pc;
 }
-#endif  // !defined(PRODUCT)
 
 FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
   const Bytecode& bytecode = Bytecode::Handle(Z, function().bytecode());
@@ -2077,10 +2153,9 @@
   kernel::BytecodeSourcePositionsIterator source_pos_iter(Z, bytecode);
   bool update_position = source_pos_iter.MoveNext();
 
-#if !defined(PRODUCT)
-  intptr_t next_pc_to_update_context_level =
-      B->is_recording_context_levels() ? 0 : bytecode_length_;
-#endif
+  kernel::BytecodeLocalVariablesIterator local_vars_iter(Z, bytecode);
+  intptr_t next_pc_to_update_scope =
+      local_vars_iter.MoveNext() ? 0 : bytecode_length_;
 
   code_ = Fragment(normal_entry);
 
@@ -2114,11 +2189,9 @@
       update_position = source_pos_iter.MoveNext();
     }
 
-#if !defined(PRODUCT)
-    if (pc_ >= next_pc_to_update_context_level) {
-      next_pc_to_update_context_level = UpdateContextLevel(bytecode, pc_);
+    if (pc_ >= next_pc_to_update_scope) {
+      next_pc_to_update_scope = UpdateScope(&local_vars_iter, pc_);
     }
-#endif
 
     BuildInstruction(KernelBytecode::DecodeOpcode(bytecode_instr_));
 
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
index 9e7edac..1e84f92 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
@@ -14,6 +14,8 @@
 namespace dart {
 namespace kernel {
 
+class BytecodeLocalVariablesIterator;
+
 // This class builds flow graph from bytecode. It is used either to compile
 // from bytecode, or generate bytecode interpreter (the latter is not
 // fully implemented yet).
@@ -107,6 +109,24 @@
     const Object& value_;
   };
 
+  // Scope declared in bytecode local variables information.
+  class BytecodeScope : public ZoneAllocated {
+   public:
+    BytecodeScope(Zone* zone,
+                  intptr_t end_pc,
+                  intptr_t context_level,
+                  BytecodeScope* parent)
+        : end_pc_(end_pc),
+          context_level_(context_level),
+          parent_(parent),
+          hidden_vars_(zone, 4) {}
+
+    const intptr_t end_pc_;
+    const intptr_t context_level_;
+    BytecodeScope* const parent_;
+    ZoneGrowableArray<LocalVariable*> hidden_vars_;
+  };
+
   Operand DecodeOperandA();
   Operand DecodeOperandB();
   Operand DecodeOperandC();
@@ -152,6 +172,7 @@
 
   void BuildInstruction(KernelBytecode::Opcode opcode);
   void BuildFfiAsFunction();
+  void BuildFfiNativeCallbackFunction();
   void BuildDebugStepCheck();
 
 #define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3)              \
@@ -167,11 +188,9 @@
                           const ExceptionHandlers& handlers,
                           GraphEntryInstr* graph_entry);
 
-#if !defined(PRODUCT)
-  // Update context level for the given bytecode PC. returns
-  // next PC where context level might need an update.
-  intptr_t UpdateContextLevel(const Bytecode& bytecode, intptr_t pc);
-#endif
+  // Update current scope, context level and local variables for the given PC.
+  // Returns next PC where scope might need an update.
+  intptr_t UpdateScope(BytecodeLocalVariablesIterator* iter, intptr_t pc);
 
   // Figure out entry points style.
   UncheckedEntryPointStyle ChooseEntryPointStyle(
@@ -214,6 +233,8 @@
   GraphEntryInstr* graph_entry_ = nullptr;
   UncheckedEntryPointStyle entry_point_style_ = UncheckedEntryPointStyle::kNone;
   bool build_debug_step_checks_ = false;
+  bool seen_parameters_scope_ = false;
+  BytecodeScope* current_scope_ = nullptr;
 };
 
 }  // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 8e221e8..870a42e 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -47,20 +47,6 @@
   const Function& function = parsed_function->function();
   ASSERT(function.is_declared_in_bytecode());
 
-  // No parsing is needed if function has bytecode attached.
-  // With one exception: implicit functions with artificial are still handled
-  // by shared flow graph builder which requires scopes/parsing.
-  if (function.HasBytecode() &&
-      (function.kind() != RawFunction::kImplicitGetter) &&
-      (function.kind() != RawFunction::kImplicitSetter) &&
-      (function.kind() != RawFunction::kImplicitStaticGetter) &&
-      (function.kind() != RawFunction::kMethodExtractor) &&
-      (function.kind() != RawFunction::kInvokeFieldDispatcher) &&
-      (function.kind() != RawFunction::kDynamicInvocationForwarder) &&
-      (function.kind() != RawFunction::kNoSuchMethodDispatcher)) {
-    return;
-  }
-
   BytecodeComponentData bytecode_component(
       &Array::Handle(helper_->zone_, GetBytecodeComponent()));
   BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
@@ -68,38 +54,6 @@
   bytecode_reader.ParseBytecodeFunction(parsed_function, function);
 }
 
-static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-              "Cleanup support for old bytecode format versions");
-bool BytecodeMetadataHelper::ReadMembers(intptr_t node_offset,
-                                         const Class& cls,
-                                         bool discard_fields) {
-  TIMELINE_DURATION(Thread::Current(), Compiler,
-                    "BytecodeMetadataHelper::ReadMembers");
-
-  ASSERT(node_offset > 0);
-  const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
-  if (md_offset < 0) {
-    return false;
-  }
-
-  ASSERT(Thread::Current()->IsMutatorThread());
-
-  BytecodeComponentData bytecode_component(
-      &Array::Handle(helper_->zone_, GetBytecodeComponent()));
-  BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
-
-  AlternativeReadingScope alt(&bytecode_reader.reader(), md_offset);
-
-  intptr_t members_offset = bytecode_component.GetMembersOffset() +
-                            bytecode_reader.reader().ReadUInt();
-
-  AlternativeReadingScope alt2(&bytecode_reader.reader(), members_offset);
-
-  bytecode_reader.ReadMembers(cls, discard_fields);
-
-  return true;
-}
-
 bool BytecodeMetadataHelper::ReadLibraries() {
   TIMELINE_DURATION(Thread::Current(), Compiler,
                     "BytecodeMetadataHelper::ReadLibraries");
@@ -112,12 +66,6 @@
   BytecodeComponentData bytecode_component(
       &Array::Handle(helper_->zone_, GetBytecodeComponent()));
 
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                "Cleanup condition");
-  if (bytecode_component.GetVersion() < 10) {
-    return false;
-  }
-
   BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
   AlternativeReadingScope alt(&bytecode_reader.reader(),
                               bytecode_component.GetLibraryIndexOffset());
@@ -167,10 +115,10 @@
     *is_empty_program = (bytecode_component.GetNumLibraries() == 0);
   }
   if (p_num_classes != nullptr) {
-    *p_num_classes = (bytecode_component.GetNumClasses() == 0);
+    *p_num_classes = bytecode_component.GetNumClasses();
   }
   if (p_num_procedures != nullptr) {
-    *p_num_procedures = (bytecode_component.GetNumCodes() == 0);
+    *p_num_procedures = bytecode_component.GetNumCodes();
   }
   return true;
 }
@@ -231,7 +179,11 @@
   ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(!function.IsImplicitGetterFunction() &&
          !function.IsImplicitSetterFunction());
-  ASSERT(code_offset > 0);
+  if (code_offset == 0) {
+    FATAL2("Function %s (kind %s) doesn't have bytecode",
+           function.ToFullyQualifiedCString(),
+           Function::KindToCString(function.kind()));
+  }
 
   AlternativeReadingScope alt(&reader_, code_offset);
   // This scope is needed to set active_class_->enclosing_ which is used to
@@ -503,6 +455,7 @@
   const int kIsAsyncFlag = 1 << 4;
   const int kIsAsyncStarFlag = 1 << 5;
   const int kIsSyncStarFlag = 1 << 6;
+  const int kIsDebuggableFlag = 1 << 7;
 
   const intptr_t flags = reader_.ReadUInt();
 
@@ -542,6 +495,7 @@
   if (Function::Cast(parent).IsAsyncOrGenerator()) {
     closure.set_is_generated_body(true);
   }
+  closure.set_is_debuggable((flags & kIsDebuggableFlag) != 0);
 
   closures_->SetAt(closureIndex, closure);
 
@@ -727,7 +681,7 @@
     kUnused4,
     kUnused5,
     kUnused6,
-    kICData,
+    kICData,  // Obsolete in bytecode v20.
     kUnused7,
     kStaticField,
     kInstanceField,
@@ -751,6 +705,7 @@
     kDirectCall,
     kInterfaceCall,
     kInstantiatedInterfaceCall,
+    kDynamicCall,
   };
 
   enum InvocationKind {
@@ -768,7 +723,6 @@
   Field& field = Field::Handle(Z);
   Class& cls = Class::Handle(Z);
   String& name = String::Handle(Z);
-  const String* simpleInstanceOf = nullptr;
   const intptr_t obj_count = pool.Length();
   for (intptr_t i = start_index; i < obj_count; ++i) {
     const intptr_t tag = reader_.ReadTag();
@@ -776,6 +730,8 @@
       case ConstantPoolTag::kInvalid:
         UNREACHABLE();
       case ConstantPoolTag::kICData: {
+        static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 20,
+                      "Cleanup ICData constant pool entry");
         intptr_t flags = reader_.ReadByte();
         InvocationKind kind =
             static_cast<InvocationKind>(flags & kInvocationKindMask);
@@ -785,10 +741,6 @@
         intptr_t arg_desc_index = reader_.ReadUInt();
         ASSERT(arg_desc_index < i);
         array ^= pool.ObjectAt(arg_desc_index);
-        if (simpleInstanceOf == nullptr) {
-          simpleInstanceOf =
-              &Library::PrivateCoreLibName(Symbols::_simpleInstanceOf());
-        }
         // Do not mangle == or call:
         //   * operator == takes an Object so its either not checked or checked
         //     at the entry because the parameter is marked covariant, neither
@@ -924,6 +876,37 @@
         // 3) Static receiver type.
         obj = ReadObject();
       } break;
+      case ConstantPoolTag::kDynamicCall: {
+        name ^= ReadObject();
+        ASSERT(name.IsSymbol());
+        array ^= ReadObject();
+        // Do not mangle == or call:
+        //   * operator == takes an Object so it is either not checked or
+        //     checked at the entry because the parameter is marked covariant,
+        //     neither of those cases require a dynamic invocation forwarder;
+        //   * we assume that all closures are entered in a checked way.
+        if (!Field::IsGetterName(name) && !FLAG_precompiled_mode &&
+            I->should_emit_strong_mode_checks() &&
+            (name.raw() != Symbols::EqualOperator().raw()) &&
+            (name.raw() != Symbols::Call().raw())) {
+          name = Function::CreateDynamicInvocationForwarderName(name);
+        }
+        static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 20,
+                      "Can use 2 slots in object pool");
+        // DynamicCall constant occupies 2 entries: selector and arguments
+        // descriptor. For backwards compatibility with ICData constants
+        // selector and arguments descriptor are packaged into UnlinkedCall
+        // object. The 2nd slot is filled with null.
+        obj = UnlinkedCall::New();
+        UnlinkedCall::Cast(obj).set_target_name(name);
+        UnlinkedCall::Cast(obj).set_args_descriptor(array);
+        pool.SetTypeAt(i, ObjectPool::EntryType::kTaggedObject,
+                       ObjectPool::Patchability::kNotPatchable);
+        pool.SetObjectAt(i, obj);
+        ++i;
+        ASSERT(i < obj_count);
+        obj = Object::null();
+      } break;
       default:
         UNREACHABLE();
     }
@@ -962,7 +945,7 @@
   if (try_block_count > 0) {
     const ObjectPool& pool = ObjectPool::Handle(Z, bytecode.object_pool());
     AbstractType& handler_type = AbstractType::Handle(Z);
-    Array& handler_types = Array::ZoneHandle(Z);
+    Array& handler_types = Array::Handle(Z);
     DescriptorList* pc_descriptors_list = new (Z) DescriptorList(64);
     ExceptionHandlerList* exception_handlers_list =
         new (Z) ExceptionHandlerList();
@@ -1003,9 +986,13 @@
                                          DeoptId::kNone,
                                          TokenPosition::kNoSource, -1);
 
+      // The exception handler keeps a zone handle of the types array, rather
+      // than a raw pointer. Do not share the handle across iterations to avoid
+      // clobbering the array.
       exception_handlers_list->AddHandler(
           try_index, outer_try_index, handler_pc, TokenPosition::kNoSource,
-          is_generated, handler_types, needs_stacktrace);
+          is_generated, Array::ZoneHandle(Z, handler_types.raw()),
+          needs_stacktrace);
     }
     const PcDescriptors& descriptors = PcDescriptors::Handle(
         Z, pc_descriptors_list->FinalizePcDescriptors(bytecode.PayloadStart()));
@@ -1037,13 +1024,9 @@
     return;
   }
 
-  intptr_t offset = reader_.ReadUInt();
-  USE(offset);
-
-#if !defined(PRODUCT)
+  const intptr_t offset = reader_.ReadUInt();
   bytecode.set_local_variables_binary_offset(
       bytecode_component_->GetLocalVariablesOffset() + offset);
-#endif
 }
 
 RawTypedData* BytecodeReaderHelper::NativeEntry(const Function& function,
@@ -1157,23 +1140,14 @@
   reader_.ReadUInt32();  // Skip main.numItems
   const intptr_t main_offset = start_offset + reader_.ReadUInt32();
 
-  intptr_t num_libraries = 0;
-  intptr_t library_index_offset = 0;
-  intptr_t libraries_offset = 0;
-  intptr_t num_classes = 0;
-  intptr_t classes_offset = 0;
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                "Cleanup condition");
-  if (version >= 10) {
-    num_libraries = reader_.ReadUInt32();
-    library_index_offset = start_offset + reader_.ReadUInt32();
+  const intptr_t num_libraries = reader_.ReadUInt32();
+  const intptr_t library_index_offset = start_offset + reader_.ReadUInt32();
 
-    reader_.ReadUInt32();  // Skip libraries.numItems
-    libraries_offset = start_offset + reader_.ReadUInt32();
+  reader_.ReadUInt32();  // Skip libraries.numItems
+  const intptr_t libraries_offset = start_offset + reader_.ReadUInt32();
 
-    num_classes = reader_.ReadUInt32();
-    classes_offset = start_offset + reader_.ReadUInt32();
-  }
+  const intptr_t num_classes = reader_.ReadUInt32();
+  const intptr_t classes_offset = start_offset + reader_.ReadUInt32();
 
   reader_.ReadUInt32();  // Skip members.numItems
   const intptr_t members_offset = start_offset + reader_.ReadUInt32();
@@ -1184,25 +1158,14 @@
   reader_.ReadUInt32();  // Skip sourcePositions.numItems
   const intptr_t source_positions_offset = start_offset + reader_.ReadUInt32();
 
-  intptr_t source_files_offset = 0;
-  intptr_t line_starts_offset = 0;
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                "Cleanup condition");
-  if (version >= 10) {
-    reader_.ReadUInt32();  // Skip sourceFiles.numItems
-    source_files_offset = start_offset + reader_.ReadUInt32();
+  reader_.ReadUInt32();  // Skip sourceFiles.numItems
+  const intptr_t source_files_offset = start_offset + reader_.ReadUInt32();
 
-    reader_.ReadUInt32();  // Skip lineStarts.numItems
-    line_starts_offset = start_offset + reader_.ReadUInt32();
-  }
+  reader_.ReadUInt32();  // Skip lineStarts.numItems
+  const intptr_t line_starts_offset = start_offset + reader_.ReadUInt32();
 
-  intptr_t local_variables_offset = 0;
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 9,
-                "Cleanup condition");
-  if (version >= 9) {
-    reader_.ReadUInt32();  // Skip localVariables.numItems
-    local_variables_offset = start_offset + reader_.ReadUInt32();
-  }
+  reader_.ReadUInt32();  // Skip localVariables.numItems
+  const intptr_t local_variables_offset = start_offset + reader_.ReadUInt32();
 
   reader_.ReadUInt32();  // Skip annotations.numItems
   const intptr_t annotations_offset = start_offset + reader_.ReadUInt32();
@@ -1303,8 +1266,6 @@
 RawObject* BytecodeReaderHelper::ReadObjectContents(uint32_t header) {
   ASSERT(((header & kReferenceBit) == 0));
 
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                "Cleanup obsolete object kinds");
   // Must be in sync with enum ObjectKind in
   // pkg/vm/lib/bytecode/object_table.dart.
   enum ObjectKind {
@@ -1313,13 +1274,13 @@
     kClass,
     kMember,
     kClosure,
-    kSimpleType,     // obsolete in v10
-    kTypeParameter,  // obsolete in v10
-    kGenericType,    // obsolete in v10
-    kFunctionType,   // obsolete in v10
+    kUnused1,
+    kUnused2,
+    kUnused3,
+    kUnused4,
     kName,
     kTypeArguments,
-    kFinalizedGenericType,  // obsolete in v10
+    kUnused5,
     kConstObject,
     kArgDesc,
     kScript,
@@ -1331,19 +1292,6 @@
   const intptr_t kFlagIsField = kFlagBit0;
   const intptr_t kFlagIsConstructor = kFlagBit1;
 
-  // SimpleType flags, must be in sync with _SimpleTypeHandle constants in
-  // pkg/vm/lib/bytecode/object_table.dart.
-  const intptr_t kFlagIsDynamic = kFlagBit0;
-  const intptr_t kFlagIsVoid = kFlagBit1;
-
-  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                "Cleanup old FunctionType flags");
-  // FunctionType flags, must be in sync with _FunctionTypeHandle constants in
-  // pkg/vm/lib/bytecode/object_table.dart.
-  const int kFlagHasOptionalPositionalParams = kFlagBit0;
-  const int kFlagHasOptionalNamedParams = kFlagBit1;
-  const int kFlagHasTypeParams = kFlagBit2;
-
   // ArgDesc flags, must be in sync with _ArgDescHandle constants in
   // pkg/vm/lib/bytecode/object_table.dart.
   const int kFlagHasNamedArgs = kFlagBit0;
@@ -1361,16 +1309,8 @@
       UNREACHABLE();
       break;
     case kLibrary: {
-      String& uri = String::Handle(Z);
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup condition");
-      if (bytecode_component_->GetVersion() < 10) {
-        uri = ReadString();
-      } else {
-        uri ^= ReadObject();
-      }
+      String& uri = String::CheckedHandle(Z, ReadObject());
       RawLibrary* library = Library::LookupLibrary(thread_, uri);
-      NoSafepointScope no_safepoint_scope(thread_);
       if (library == Library::null()) {
         // We do not register expression evaluation libraries with the VM:
         // The expression evaluation functions should be GC-able as soon as
@@ -1379,7 +1319,15 @@
           ASSERT(expression_evaluation_library_ != nullptr);
           return expression_evaluation_library_->raw();
         }
+#if !defined(PRODUCT)
+        ASSERT(Isolate::Current()->HasAttemptedReload());
+        const String& msg = String::Handle(
+            Z,
+            String::NewFormatted("Unable to find library %s", uri.ToCString()));
+        Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
         FATAL1("Unable to find library %s", uri.ToCString());
+#endif
       }
       return library;
     }
@@ -1395,13 +1343,21 @@
         return cls;
       }
       RawClass* cls = library.LookupLocalClass(class_name);
-      NoSafepointScope no_safepoint_scope(thread_);
       if (cls == Class::null()) {
         if (IsExpressionEvaluationLibrary(library)) {
           return H.GetExpressionEvaluationRealClass();
         }
+#if !defined(PRODUCT)
+        ASSERT(Isolate::Current()->HasAttemptedReload());
+        const String& msg = String::Handle(
+            Z,
+            String::NewFormatted("Unable to find class %s in %s",
+                                 class_name.ToCString(), library.ToCString()));
+        Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
         FATAL2("Unable to find class %s in %s", class_name.ToCString(),
                library.ToCString());
+#endif
       }
       return cls;
     }
@@ -1410,10 +1366,17 @@
       String& name = String::CheckedHandle(Z, ReadObject());
       if ((flags & kFlagIsField) != 0) {
         RawField* field = cls.LookupField(name);
-        NoSafepointScope no_safepoint_scope(thread_);
         if (field == Field::null()) {
+#if !defined(PRODUCT)
+          ASSERT(Isolate::Current()->HasAttemptedReload());
+          const String& msg = String::Handle(
+              Z, String::NewFormatted("Unable to find field %s in %s",
+                                      name.ToCString(), cls.ToCString()));
+          Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
           FATAL2("Unable to find field %s in %s", name.ToCString(),
                  cls.ToCString());
+#endif
         }
         return field;
       } else {
@@ -1426,10 +1389,6 @@
           return scoped_function_.raw();
         }
         RawFunction* function = cls.LookupFunction(name);
-        {
-          // To verify that it's OK to hold raw function pointer at this point.
-          NoSafepointScope no_safepoint_scope(thread_);
-        }
         if (function == Function::null()) {
           // When requesting a getter, also return method extractors.
           if (Field::IsGetterName(name)) {
@@ -1444,8 +1403,16 @@
               }
             }
           }
+#if !defined(PRODUCT)
+          ASSERT(Isolate::Current()->HasAttemptedReload());
+          const String& msg = String::Handle(
+              Z, String::NewFormatted("Unable to find function %s in %s",
+                                      name.ToCString(), cls.ToCString()));
+          Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
           FATAL2("Unable to find function %s in %s", name.ToCString(),
                  cls.ToCString());
+#endif
         }
         return function;
       }
@@ -1455,80 +1422,6 @@
       const intptr_t closure_index = reader_.ReadUInt();
       return closures_->At(closure_index);
     }
-    case kSimpleType: {
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup");
-      const Class& cls = Class::CheckedHandle(Z, ReadObject());
-      if ((flags & kFlagIsDynamic) != 0) {
-        ASSERT(cls.IsNull());
-        return AbstractType::dynamic_type().raw();
-      }
-      if ((flags & kFlagIsVoid) != 0) {
-        ASSERT(cls.IsNull());
-        return AbstractType::void_type().raw();
-      }
-      return cls.DeclarationType();
-    }
-    case kTypeParameter: {
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup");
-      Object& parent = Object::Handle(Z, ReadObject());
-      const intptr_t index_in_parent = reader_.ReadUInt();
-      TypeArguments& type_parameters = TypeArguments::Handle(Z);
-      if (parent.IsClass()) {
-        type_parameters = Class::Cast(parent).type_parameters();
-      } else if (parent.IsFunction()) {
-        if (Function::Cast(parent).IsFactory()) {
-          // For factory constructors VM uses type parameters of a class
-          // instead of constructor's type parameters.
-          parent = Function::Cast(parent).Owner();
-          type_parameters = Class::Cast(parent).type_parameters();
-        } else {
-          type_parameters = Function::Cast(parent).type_parameters();
-        }
-      } else if (parent.IsNull()) {
-        ASSERT(function_type_type_parameters_ != nullptr);
-        type_parameters = function_type_type_parameters_->raw();
-      } else {
-        UNREACHABLE();
-      }
-      AbstractType& type =
-          AbstractType::Handle(Z, type_parameters.TypeAt(index_in_parent));
-      // TODO(alexmarkov): figure out how to skip this type finalization
-      // (consider finalizing type parameters of classes/functions eagerly).
-      return ClassFinalizer::FinalizeType(*active_class_->klass, type);
-    }
-    case kGenericType: {
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup");
-      const Class& cls = Class::CheckedHandle(Z, ReadObject());
-      const TypeArguments& type_arguments =
-          TypeArguments::Handle(Z, ReadTypeArguments());
-      const Type& type = Type::Handle(
-          Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
-      return ClassFinalizer::FinalizeType(*active_class_->klass, type);
-    }
-    case kFunctionType: {
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup");
-      Function& signature_function = Function::ZoneHandle(
-          Z, Function::NewSignatureFunction(*active_class_->klass,
-                                            active_class_->enclosing != NULL
-                                                ? *active_class_->enclosing
-                                                : Function::null_function(),
-                                            TokenPosition::kNoSource));
-
-      // This scope is needed to set active_class_->enclosing_ which is used
-      // to assign parent function for function types.
-      ActiveEnclosingFunctionScope active_enclosing_function(
-          active_class_, &signature_function);
-
-      return ReadFunctionSignature(
-          signature_function, (flags & kFlagHasOptionalPositionalParams) != 0,
-          (flags & kFlagHasOptionalNamedParams) != 0,
-          (flags & kFlagHasTypeParams) != 0,
-          /* has_positional_param_names = */ false);
-    }
     case kName: {
       const Library& library = Library::CheckedHandle(Z, ReadObject());
       if (library.IsNull()) {
@@ -1542,17 +1435,6 @@
     case kTypeArguments: {
       return ReadTypeArguments();
     }
-    case kFinalizedGenericType: {
-      static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                    "Cleanup");
-      const Class& cls = Class::CheckedHandle(Z, ReadObject());
-      const TypeArguments& type_arguments =
-          TypeArguments::CheckedHandle(Z, ReadObject());
-      const Type& type = Type::Handle(
-          Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
-      type.SetIsFinalized();
-      return type.Canonicalize();
-    }
     case kConstObject: {
       const intptr_t tag = flags / kFlagBit0;
       return ReadConstObject(tag);
@@ -2827,11 +2709,14 @@
     const KBCInstr* instr =
         reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
     if (KernelBytecode::IsEntryOptionalOpcode(instr)) {
-      const intptr_t num_fixed_params = KernelBytecode::DecodeA(instr);
+      // Note that number of fixed parameters may not match 'A' operand of
+      // EntryOptional bytecode as [function] could be an implicit closure
+      // function with an extra implicit argument, while bytecode corresponds
+      // to a static function without any implicit arguments.
+      const intptr_t num_fixed_params = function.num_fixed_parameters();
       const intptr_t num_opt_pos_params = KernelBytecode::DecodeB(instr);
       const intptr_t num_opt_named_params = KernelBytecode::DecodeC(instr);
       instr = KernelBytecode::Next(instr);
-      ASSERT(num_fixed_params == function.num_fixed_parameters());
       ASSERT(num_opt_pos_params == function.NumOptionalPositionalParameters());
       ASSERT(num_opt_named_params == function.NumOptionalNamedParameters());
       ASSERT((num_opt_pos_params == 0) || (num_opt_named_params == 0));
@@ -2877,41 +2762,37 @@
 void BytecodeReaderHelper::ParseBytecodeFunction(
     ParsedFunction* parsed_function,
     const Function& function) {
+  // Handle function kinds which don't have a user-defined body first.
   switch (function.kind()) {
     case RawFunction::kImplicitClosureFunction:
       ParseForwarderFunction(parsed_function, function,
                              Function::Handle(Z, function.parent_function()));
-      break;
+      return;
     case RawFunction::kDynamicInvocationForwarder:
       ParseForwarderFunction(
           parsed_function, function,
           Function::Handle(Z,
                            function.GetTargetOfDynamicInvocationForwarder()));
-      break;
+      return;
     case RawFunction::kImplicitGetter:
     case RawFunction::kImplicitSetter:
-      BytecodeScopeBuilder(parsed_function).BuildScopes();
-      break;
-    case RawFunction::kImplicitStaticGetter: {
-      if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
-        ReadCode(function, function.bytecode_offset());
-      } else {
-        BytecodeScopeBuilder(parsed_function).BuildScopes();
-      }
-      break;
-    }
-    case RawFunction::kFieldInitializer:
-      ReadCode(function, function.bytecode_offset());
-      break;
     case RawFunction::kMethodExtractor:
       BytecodeScopeBuilder(parsed_function).BuildScopes();
-      break;
+      return;
+    case RawFunction::kImplicitStaticGetter: {
+      if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
+        break;
+      } else {
+        BytecodeScopeBuilder(parsed_function).BuildScopes();
+        return;
+      }
+    }
     case RawFunction::kRegularFunction:
     case RawFunction::kGetterFunction:
     case RawFunction::kSetterFunction:
     case RawFunction::kClosureFunction:
     case RawFunction::kConstructor:
-      ReadCode(function, function.bytecode_offset());
+    case RawFunction::kFieldInitializer:
       break;
     case RawFunction::kNoSuchMethodDispatcher:
     case RawFunction::kInvokeFieldDispatcher:
@@ -2921,6 +2802,28 @@
       UNREACHABLE();
       break;
   }
+
+  // We only reach here if function has a bytecode body. Make sure it is
+  // loaded and collect information about covariant parameters.
+
+  if (!function.HasBytecode()) {
+    ReadCode(function, function.bytecode_offset());
+    ASSERT(function.HasBytecode());
+  }
+
+  // TODO(alexmarkov): simplify access to covariant / generic_covariant_impl
+  //  flags of parameters so we won't need to read them separately.
+  if (!parsed_function->HasCovariantParametersInfo()) {
+    const intptr_t num_params = function.NumParameters();
+    BitVector* covariant_parameters = new (Z) BitVector(Z, num_params);
+    BitVector* generic_covariant_impl_parameters =
+        new (Z) BitVector(Z, num_params);
+    ReadParameterCovariance(function, covariant_parameters,
+                            generic_covariant_impl_parameters);
+    parsed_function->SetCovariantParameters(covariant_parameters);
+    parsed_function->SetGenericCovariantImplParameters(
+        generic_covariant_impl_parameters);
+  }
 }
 
 void BytecodeReaderHelper::ParseForwarderFunction(
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 3ca2ad45..ec915dd 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -26,11 +26,6 @@
 
   void ParseBytecodeFunction(ParsedFunction* parsed_function);
 
-  // Reads members associated with given [node_offset] and fills in [cls].
-  // Discards fields if [discard_fields] is true.
-  // Returns true if class members are loaded.
-  bool ReadMembers(intptr_t node_offset, const Class& cls, bool discard_fields);
-
   // Read all library declarations.
   bool ReadLibraries();
 
@@ -369,8 +364,9 @@
 
 class BytecodeSourcePositionsIterator : ValueObject {
  public:
-  // This constant should match corresponding constant in class SourcePositions
-  // (pkg/vm/lib/bytecode/source_positions.dart).
+  // These constants should match corresponding constants in class
+  // SourcePositions (pkg/vm/lib/bytecode/source_positions.dart).
+  static const intptr_t kSyntheticCodeMarker = -1;
   static const intptr_t kYieldPointMarker = -2;
 
   BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
@@ -400,7 +396,11 @@
 
   uword PcOffset() const { return cur_bci_; }
 
-  TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
+  TokenPosition TokenPos() const {
+    return (cur_token_pos_ == kSyntheticCodeMarker)
+               ? TokenPosition::kNoSource
+               : TokenPosition(cur_token_pos_);
+  }
 
   bool IsYieldPoint() const { return is_yield_point_; }
 
@@ -412,7 +412,6 @@
   bool is_yield_point_ = false;
 };
 
-#if !defined(PRODUCT)
 class BytecodeLocalVariablesIterator : ValueObject {
  public:
   // These constants should match corresponding constants in
@@ -465,6 +464,7 @@
     return true;
   }
 
+  bool IsDone() const { return entries_remaining_ == 0; }
   intptr_t Kind() const { return cur_kind_and_flags_ & kKindMask; }
   bool IsScope() const { return Kind() == kScope; }
   bool IsVariableDeclaration() const { return Kind() == kVariableDeclaration; }
@@ -522,7 +522,6 @@
   TokenPosition cur_declaration_token_pos_ = TokenPosition::kNoSource;
   TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
 };
-#endif  // !defined(PRODUCT)
 
 bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
                                                Zone* zone);
diff --git a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
index e3d3f50c..8da6b6e 100644
--- a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
@@ -73,7 +73,7 @@
 
       // Type check all parameters by default.
       // This may be overridden with parameter flags in
-      // BytecodeReaderHelper::ParseImplicitClosureFunction.
+      // BytecodeReaderHelper::ParseForwarderFunction.
       AddParameters(function, LocalVariable::kDoTypeCheck);
       break;
     }
@@ -114,7 +114,7 @@
 
       // Type check all parameters by default.
       // This may be overridden with parameter flags in
-      // BytecodeReaderHelper::ParseImplicitClosureFunction.
+      // BytecodeReaderHelper::ParseForwarderFunction.
       AddParameters(function, LocalVariable::kDoTypeCheck);
       break;
     }
diff --git a/runtime/vm/compiler/frontend/constant_evaluator.cc b/runtime/vm/compiler/frontend/constant_evaluator.cc
index e433e26..b8409a8 100644
--- a/runtime/vm/compiler/frontend/constant_evaluator.cc
+++ b/runtime/vm/compiler/frontend/constant_evaluator.cc
@@ -98,6 +98,7 @@
       case kSetConcatenation:
       case kMapConcatenation:
       case kInstanceCreation:
+      case kFileUriExpression:
         // These only occur inside unevaluated constants, so if we decide to
         // remove support for late evaluation of environment constants from
         // dill files in the VM, an implementation here will not be necessary.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index fa00a60..7068b74 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1164,8 +1164,9 @@
     case kSetConcatenation:
     case kMapConcatenation:
     case kInstanceCreation:
-      // Collection concatenation and instance creation operations are removed
-      // by the constant evaluator.
+    case kFileUriExpression:
+      // Collection concatenation, instance creation operations and
+      // in-expression URI changes are removed by the constant evaluator.
       UNREACHABLE();
       break;
     case kIsExpression:
@@ -3056,8 +3057,12 @@
     ++argument_count;
   }
 
-  if (compiler::ffi::IsAsFunctionInternal(Z, H.isolate(), target)) {
+  const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
+  if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
     return BuildFfiAsFunctionInternal();
+  } else if (FLAG_precompiled_mode &&
+             recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
+    return BuildFfiNativeCallbackFunction();
   }
 
   Fragment instructions;
@@ -3065,7 +3070,7 @@
 
   const bool special_case_nop_async_stack_trace_helper =
       !FLAG_causal_async_stacks &&
-      target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper;
+      recognized_kind == MethodRecognizer::kAsyncStackTraceHelper;
 
   const bool special_case_unchecked_cast =
       klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) &&
@@ -5040,6 +5045,65 @@
   return code;
 }
 
+Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
+#if defined(TARGET_ARCH_DBC)
+  UNREACHABLE();
+#else
+  // The call-site must look like this (guaranteed by the FE which inserts it):
+  //
+  //   _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
+  //
+  // The FE also guarantees that all three arguments are constants.
+
+  const intptr_t argc = ReadUInt();  // read argument count
+  ASSERT(argc == 2);                 // target, exceptionalReturn
+
+  const intptr_t list_length = ReadListLength();  // read types list length
+  ASSERT(list_length == 1);                       // native signature
+  const TypeArguments& type_arguments =
+      T.BuildTypeArguments(list_length);  // read types.
+  ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
+  const Function& native_sig = Function::Handle(
+      Z, Type::Cast(AbstractType::Handle(Z, type_arguments.TypeAt(0)))
+             .signature());
+
+  Fragment code;
+  const intptr_t positional_count =
+      ReadListLength();  // read positional argument count
+  ASSERT(positional_count == 2);
+
+  // Read target expression and extract the target function.
+  code += BuildExpression();  // build first positional argument (target)
+  Definition* target_def = B->Peek();
+  ASSERT(target_def->IsConstant());
+  const Closure& target_closure =
+      Closure::Cast(target_def->AsConstant()->value());
+  ASSERT(!target_closure.IsNull());
+  Function& target = Function::Handle(Z, target_closure.function());
+  ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
+  target = target.parent_function();
+  code += Drop();
+
+  // Build second positional argument (exceptionalReturn).
+  code += BuildExpression();
+  Definition* exceptional_return_def = B->Peek();
+  ASSERT(exceptional_return_def->IsConstant());
+  const Instance& exceptional_return =
+      Instance::Cast(exceptional_return_def->AsConstant()->value());
+  code += Drop();
+
+  const intptr_t named_args_len =
+      ReadListLength();  // skip (empty) named arguments list
+  ASSERT(named_args_len == 0);
+
+  const Function& result =
+      Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
+                                  native_sig, target, exceptional_return));
+  code += Constant(result);
+  return code;
+#endif
+}
+
 }  // namespace kernel
 }  // namespace dart
 
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index e8b36bd..0eab5b9b 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -353,6 +353,10 @@
   // Kernel buffer and pushes the resulting closure.
   Fragment BuildFfiAsFunctionInternal();
 
+  // Build build FG for '_nativeCallbackFunction'. Reads an Arguments from the
+  // Kernel buffer and pushes the resulting Function object.
+  Fragment BuildFfiNativeCallbackFunction();
+
   FlowGraphBuilder* flow_graph_builder_;
   ActiveClass* const active_class_;
   TypeTranslator type_translator_;
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index bed6c0f..2f8fc9f 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -461,8 +461,9 @@
     case kSetConcatenation:
     case kMapConcatenation:
     case kInstanceCreation:
-      // Collection concatenation and instance creation operations are removed
-      // by the constant evaluator.
+    case kFileUriExpression:
+      // Collection concatenation, instance creation operations and
+      // in-expression URI changes are removed by the constant evaluator.
       UNREACHABLE();
       break;
     case kIsExpression:
@@ -645,7 +646,7 @@
           ReadPosition();                    // read jth position.
           CalculateExpressionFingerprint();  // read jth expression.
         }
-        BuildHash(ReadBool());            // read is_default.
+        BuildHash(static_cast<uint32_t>(ReadBool()));  // read is_default.
         CalculateStatementFingerprint();  // read body.
       }
       return;
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 2169ebd..fbca763 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2397,6 +2397,7 @@
   // do not appear in the type arguments to a any Pointer classes in an FFI
   // signature.
   ASSERT(args.IsNull() || args.IsInstantiated());
+  args = args.Canonicalize();
 
   Fragment code;
   code += Constant(args);
@@ -2450,14 +2451,6 @@
     const Representation native_representation) {
   Fragment body;
 
-  // Return 0 for void.
-  if (compiler::ffi::NativeTypeIsVoid(ffi_type)) {
-    body += Drop();
-    body += IntConstant(0);
-    body += UnboxTruncate(kUnboxedFfiIntPtr);
-    return body;
-  }
-
   // Check for 'null'.
   body += LoadLocal(MakeTemporary());
   body <<= new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()),
@@ -2614,9 +2607,20 @@
                       /*needs_stacktrace=*/false, /*is_synthesized=*/true);
 
   // Return the "exceptional return" value given in 'fromFunction'.
-  catch_body += Constant(
-      Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
-  catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
+  //
+  // For pointer and void return types, the exceptional return is always null --
+  // return 0 instead.
+  if (compiler::ffi::NativeTypeIsPointer(ffi_type) ||
+      compiler::ffi::NativeTypeIsVoid(ffi_type)) {
+    ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
+    catch_body += IntConstant(0);
+    catch_body += UnboxTruncate(kUnboxedFfiIntPtr);
+  } else {
+    catch_body += Constant(
+        Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
+    catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
+  }
+
   catch_body += NativeReturn(result_rep);
   --catch_depth_;
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 90b63be..4469fce 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2248,8 +2248,9 @@
     case kSetConcatenation:
     case kMapConcatenation:
     case kInstanceCreation:
-      // Collection concatenation and instance creation operations are removed
-      // by the constant evaluator.
+    case kFileUriExpression:
+      // Collection concatenation, instance creation operations and
+      // in-expression URI changes are removed by the constant evaluator.
       UNREACHABLE();
       break;
     case kIsExpression:
@@ -2806,6 +2807,9 @@
 
   const Class& klass = Class::Handle(Z, H.LookupClassByKernelClass(klass_name));
   ASSERT(!klass.IsNull());
+  if (klass.is_declared_in_bytecode()) {
+    klass.EnsureDeclarationLoaded();
+  }
   if (simple) {
     if (finalize_ || klass.is_type_finalized()) {
       // Fast path for non-generic types: retrieve or populate the class's only
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 87a593b..8f9371b 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -689,12 +689,12 @@
   void SetNext(Field field) { next_read_ = field; }
   void SetJustRead(Field field) { next_read_ = field + 1; }
 
-  bool is_abstract() const { return flags_ & Flag::kIsAbstract; }
+  bool is_abstract() const { return (flags_ & Flag::kIsAbstract) != 0; }
 
-  bool is_enum_class() const { return flags_ & Flag::kIsEnumClass; }
+  bool is_enum_class() const { return (flags_ & Flag::kIsEnumClass) != 0; }
 
   bool is_transformed_mixin_application() const {
-    return flags_ & Flag::kIsEliminatedMixin;
+    return (flags_ & Flag::kIsEliminatedMixin) != 0;
   }
 
   NameIndex canonical_name_;
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index fcf01e8..8e4a4c6 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -789,8 +789,9 @@
     case kSetConcatenation:
     case kMapConcatenation:
     case kInstanceCreation:
-      // Collection concatenation and instance creation operations are removed
-      // by the constant evaluator.
+    case kFileUriExpression:
+      // Collection concatenation, instance creation operations and
+      // in-expression URI changes are removed by the constant evaluator.
       UNREACHABLE();
       break;
     case kIsExpression:
@@ -1637,6 +1638,7 @@
     raw_variable =
         new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
                           symbol, AbstractType::dynamic_type());
+    raw_variable->set_is_forced_stack();
     const bool ok = scope_->AddVariable(raw_variable);
     ASSERT(ok);
   } else {
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index d251b3e..728aee5 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -278,15 +278,22 @@
 
   // Value check/conversion.
   switch (array_cid) {
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+#if defined(TARGET_ARCH_IS_32_BIT)
+      // On 32-bit architectures, clamping operations need the exact value
+      // for proper operations. On 64-bit architectures, kUnboxedIntPtr
+      // maps to kUnboxedInt64. All other situations get away with
+      // truncating even non-smi values.
+      builder.AddInstruction(new CheckSmiInstr(new Value(value), DeoptId::kNone,
+                                               builder.TokenPos()));
+      FALL_THROUGH;
+#endif
     case kTypedDataInt8ArrayCid:
     case kTypedDataInt16ArrayCid:
     case kTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
     case kTypedDataUint16ArrayCid:
     case kExternalTypedDataUint8ArrayCid:
-    case kExternalTypedDataUint8ClampedArrayCid:
-      builder.AddInstruction(new CheckSmiInstr(new Value(value), DeoptId::kNone,
-                                               builder.TokenPos()));
       value = builder.AddUnboxInstr(kUnboxedIntPtr, new Value(value),
                                     /* is_checked = */ false);
       value->AsUnboxInteger()->mark_truncating();
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index b2b2c29..5bf7d0a 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -119,7 +119,6 @@
     // These flags are constants with PRODUCT and DART_PRECOMPILED_RUNTIME.
     FLAG_deoptimize_alot = false;  // Used in some tests.
     FLAG_deoptimize_every = 0;     // Used in some tests.
-    FLAG_load_deferred_eagerly = true;
     FLAG_use_osr = false;
 #endif
   }
@@ -335,9 +334,7 @@
       : parsed_function_(parsed_function),
         optimized_(optimized),
         osr_id_(osr_id),
-        thread_(Thread::Current()),
-        loading_invalidation_gen_at_start_(
-            isolate()->loading_invalidation_gen()) {}
+        thread_(Thread::Current()) {}
 
   RawCode* Compile(CompilationPipeline* pipeline);
 
@@ -347,9 +344,6 @@
   intptr_t osr_id() const { return osr_id_; }
   Thread* thread() const { return thread_; }
   Isolate* isolate() const { return thread_->isolate(); }
-  intptr_t loading_invalidation_gen_at_start() const {
-    return loading_invalidation_gen_at_start_;
-  }
   RawCode* FinalizeCompilation(compiler::Assembler* assembler,
                                FlowGraphCompiler* graph_compiler,
                                FlowGraph* flow_graph);
@@ -359,7 +353,6 @@
   const bool optimized_;
   const intptr_t osr_id_;
   Thread* const thread_;
-  const intptr_t loading_invalidation_gen_at_start_;
 
   DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper);
 };
@@ -439,13 +432,6 @@
           }
         }
       }
-      if (loading_invalidation_gen_at_start() !=
-          isolate()->loading_invalidation_gen()) {
-        code_is_valid = false;
-        if (trace_compiler) {
-          THR_Print("--> FAIL: Loading invalidation.");
-        }
-      }
       if (!thread()
                ->compiler_state()
                .cha()
@@ -504,14 +490,6 @@
       function.SetUsageCounter(0);
     }
   }
-  if (parsed_function()->HasDeferredPrefixes()) {
-    ASSERT(!FLAG_load_deferred_eagerly);
-    ZoneGrowableArray<const LibraryPrefix*>* prefixes =
-        parsed_function()->deferred_prefixes();
-    for (intptr_t i = 0; i < prefixes->length(); i++) {
-      (*prefixes)[i]->RegisterDependentCode(code);
-    }
-  }
   return code.raw();
 }
 
@@ -629,7 +607,12 @@
       CompilerPassState pass_state(thread(), flow_graph, &speculative_policy);
       pass_state.reorder_blocks = reorder_blocks;
 
-      if (optimized()) {
+      if (function.ForceOptimize()) {
+        ASSERT(optimized());
+        TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
+        flow_graph = CompilerPass::RunForceOptimizedPipeline(CompilerPass::kJIT,
+                                                             &pass_state);
+      } else if (optimized()) {
         TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
 
         pass_state.inline_id_to_function.Add(&function);
@@ -644,7 +627,7 @@
         JitCallSpecializer call_specializer(flow_graph, &speculative_policy);
         pass_state.call_specializer = &call_specializer;
 
-        CompilerPass::RunPipeline(CompilerPass::kJIT, &pass_state);
+        flow_graph = CompilerPass::RunPipeline(CompilerPass::kJIT, &pass_state);
       }
 
       ASSERT(pass_state.inline_id_to_function.length() ==
@@ -743,11 +726,12 @@
                                         intptr_t osr_id) {
   ASSERT(!FLAG_precompiled_mode);
   ASSERT(!optimized || function.WasCompiled() || function.ForceOptimize());
+  ASSERT(function.is_background_optimizable() ||
+         !Compiler::IsBackgroundCompilation());
   if (function.ForceOptimize()) optimized = true;
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
-    Isolate* const isolate = thread->isolate();
     StackZone stack_zone(thread);
     Zone* const zone = stack_zone.GetZone();
     const bool trace_compiler =
@@ -768,8 +752,6 @@
                 function.token_pos().ToCString(), token_size);
     }
     // Makes sure no classes are loaded during parsing in background.
-    const intptr_t loading_invalidation_gen_at_start =
-        isolate->loading_invalidation_gen();
     {
       HANDLESCOPE(thread);
       pipeline->ParseFunction(parsed_function);
@@ -777,17 +759,6 @@
 
     CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
 
-    if (Compiler::IsBackgroundCompilation()) {
-      ASSERT(function.is_background_optimizable());
-      if ((loading_invalidation_gen_at_start !=
-           isolate->loading_invalidation_gen())) {
-        // Loading occured while parsing. We need to abort here because state
-        // changed while compiling.
-        Compiler::AbortBackgroundCompilation(
-            DeoptId::kNone,
-            "Invalidated state during parsing because of script loading");
-      }
-    }
 
     const Code& result = Code::Handle(helper.Compile(pipeline));
 
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.cc b/runtime/vm/compiler/jit/jit_call_specializer.cc
index 4abf730..a13bffc 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.cc
+++ b/runtime/vm/compiler/jit/jit_call_specializer.cc
@@ -51,15 +51,14 @@
 }
 
 void JitCallSpecializer::ReplaceWithStaticCall(InstanceCallInstr* instr,
-                                               const ICData& unary_checks,
                                                const Function& target,
                                                intptr_t call_count) {
   StaticCallInstr* call =
       StaticCallInstr::FromCall(Z, instr, target, call_count);
-  if (unary_checks.NumberOfChecks() == 1 &&
-      unary_checks.GetExactnessAt(0).IsExact()) {
-    if (unary_checks.GetExactnessAt(0).IsTriviallyExact()) {
-      flow_graph()->AddExactnessGuard(instr, unary_checks.GetCidAt(0));
+  const CallTargets& targets = instr->Targets();
+  if (targets.IsMonomorphic() && targets.MonomorphicExactness().IsExact()) {
+    if (targets.MonomorphicExactness().IsTriviallyExact()) {
+      flow_graph()->AddExactnessGuard(instr, targets.MonomorphicReceiverCid());
     }
     call->set_entry_kind(Code::EntryKind::kUnchecked);
   }
@@ -71,9 +70,11 @@
 // TODO(dartbug.com/30635) Evaluate how much this can be shared with
 // AotCallSpecializer.
 void JitCallSpecializer::VisitInstanceCall(InstanceCallInstr* instr) {
-  if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
-    return;
+  const CallTargets& targets = instr->Targets();
+  if (targets.is_empty()) {
+    return;  // No feedback.
   }
+
   const Token::Kind op_kind = instr->token_kind();
 
   // Type test is special as it always gets converted into inlined code.
@@ -82,15 +83,10 @@
     return;
   }
 
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
-
-  if ((op_kind == Token::kASSIGN_INDEX) &&
-      TryReplaceWithIndexedOp(instr, &unary_checks)) {
+  if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
     return;
   }
-  if ((op_kind == Token::kINDEX) &&
-      TryReplaceWithIndexedOp(instr, &unary_checks)) {
+  if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
     return;
   }
 
@@ -114,22 +110,18 @@
   if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
     return;
   }
-  if ((op_kind == Token::kSET) &&
-      TryInlineInstanceSetter(instr, unary_checks)) {
+  if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) {
     return;
   }
   if (TryInlineInstanceMethod(instr)) {
     return;
   }
 
-  const CallTargets& targets = *CallTargets::CreateAndExpand(Z, unary_checks);
-
   bool has_one_target = targets.HasSingleTarget();
-
   if (has_one_target) {
     // Check if the single target is a polymorphic target, if it is,
     // we don't have one target.
-    const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
+    const Function& target = targets.FirstTarget();
     if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
       has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
                            targets) != Type::null();
@@ -141,12 +133,10 @@
   }
 
   if (has_one_target) {
-    const Function& target =
-        Function::ZoneHandle(Z, unary_checks.GetTargetAt(0));
+    const Function& target = targets.FirstTarget();
     if (flow_graph()->CheckForInstanceCall(instr, target.kind()) ==
         FlowGraph::ToCheck::kNoCheck) {
-      ReplaceWithStaticCall(instr, unary_checks, target,
-                            targets.AggregateCallCount());
+      ReplaceWithStaticCall(instr, target, targets.AggregateCallCount());
       return;
     }
   }
@@ -163,30 +153,13 @@
   // non-deopting megamorphic call stub when it sees new receiver classes.
   if (has_one_target && FLAG_polymorphic_with_deopt &&
       (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) ||
-       unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+       targets.length() <= FLAG_max_polymorphic_checks)) {
     // Type propagation has not run yet, we cannot eliminate the check.
-    // TODO(erikcorry): The receiver check should use the off-heap targets
-    // array, not the IC array.
-
-    // After we determined `targets.HasSingleTarget()` the mutator might have
-    // updated the megamorphic cache by adding more entries with *different*
-    // targets.
-    //
-    // We therefore have to ensure the class check we insert is only valid for
-    // precisely the [targets] classes we have based our decision upon.
-    //
-    // (i.e. we cannot use [AddReceiverCheck]/[AddCheckClass], since it
-    //  internally consults megmorphic cache again, which can return a superset
-    //  of the classes - possibly with different targets)
-    //
-    AddCheckClass(instr->Receiver()->definition(), targets, instr->deopt_id(),
-                  instr->env(), instr);
+    AddReceiverCheck(instr);
 
     // Call can still deoptimize, do not detach environment from instr.
-    const Function& target =
-        Function::ZoneHandle(Z, unary_checks.GetTargetAt(0));
-    ReplaceWithStaticCall(instr, unary_checks, target,
-                          targets.AggregateCallCount());
+    const Function& target = targets.FirstTarget();
+    ReplaceWithStaticCall(instr, target, targets.AggregateCallCount());
   } else {
     PolymorphicInstanceCallInstr* call =
         new (Z) PolymorphicInstanceCallInstr(instr, targets,
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.h b/runtime/vm/compiler/jit/jit_call_specializer.h
index 19c1aae..ea35fa9 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.h
+++ b/runtime/vm/compiler/jit/jit_call_specializer.h
@@ -36,7 +36,6 @@
       Value* context_value);
 
   void ReplaceWithStaticCall(InstanceCallInstr* instr,
-                             const ICData& unary_checks,
                              const Function& target,
                              intptr_t call_count);
 
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 4b0c880..27e1bb1 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -145,6 +145,8 @@
   V(::, _classRangeCheck, ClassRangeCheck, 0x2ae76b84)                         \
   V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0)                      \
   V(::, _abi, FfiAbi, 0x0)                                                     \
+  V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x0)                       \
+  V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x0)               \
 
 // List of intrinsics:
 // (class-name, function-name, intrinsification method, fingerprint).
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 1d651dc..e7f6f80 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -357,7 +357,7 @@
 }
 
 intptr_t Class::NumTypeArguments(const dart::Class& klass) {
-  return klass.NumTypeArguments() > 0;
+  return klass.NumTypeArguments();
 }
 
 bool Class::HasTypeArgumentsField(const dart::Class& klass) {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index cb38030..ef2bc61 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -21,6 +21,7 @@
 #include "platform/globals.h"
 #include "vm/allocation.h"
 #include "vm/bitfield.h"
+#include "vm/bss_relocs.h"
 #include "vm/class_id.h"
 #include "vm/code_entry_kind.h"
 #include "vm/constants.h"
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 2ab5d44..3e8a5a4 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -397,7 +397,7 @@
     __ ldr(R1, Address(PC, 0));
     __ b(&call);
     __ Emit(
-        reinterpret_cast<int32_t>(&DLRT_GetThreadForNativeCallbackTrampoline));
+        reinterpret_cast<intptr_t>(&DLRT_GetThreadForNativeCallbackTrampoline));
 
     __ Bind(&call);
     __ blx(R1);
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index bda63cc..f8d4489 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -745,11 +745,11 @@
   // Magic value of bytecode files.
   static const intptr_t kMagicValue = 0x44424332;  // 'DBC2'
   // Minimum bytecode format version supported by VM.
-  static const intptr_t kMinSupportedBytecodeFormatVersion = 7;
+  static const intptr_t kMinSupportedBytecodeFormatVersion = 10;
   // Maximum bytecode format version supported by VM.
   // The range of supported versions should include version produced by bytecode
   // generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
-  static const intptr_t kMaxSupportedBytecodeFormatVersion = 19;
+  static const intptr_t kMaxSupportedBytecodeFormatVersion = 20;
 
   enum Opcode {
 #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
@@ -978,8 +978,6 @@
   // - The bytecode compiler may emit a DebugStepCheck call.
   DART_FORCE_INLINE static bool IsDebugCheckedOpcode(const KBCInstr* instr) {
     switch (DecodeOpcode(instr)) {
-      case KernelBytecode::kStoreStaticTOS:
-      case KernelBytecode::kStoreStaticTOS_Wide:
       case KernelBytecode::kDebugCheck:
       case KernelBytecode::kDirectCall:
       case KernelBytecode::kDirectCall_Wide:
@@ -994,7 +992,6 @@
       case KernelBytecode::kDynamicCall:
       case KernelBytecode::kDynamicCall_Wide:
       case KernelBytecode::kReturnTOS:
-      case KernelBytecode::kThrow:
       case KernelBytecode::kEqualsNull:
       case KernelBytecode::kNegateInt:
       case KernelBytecode::kNegateDouble:
diff --git a/runtime/vm/cpu_arm.h b/runtime/vm/cpu_arm.h
index 35e7dd8..6f5b774 100644
--- a/runtime/vm/cpu_arm.h
+++ b/runtime/vm/cpu_arm.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_CPU_ARM_H_
 #define RUNTIME_VM_CPU_ARM_H_
 
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_arm.h directly; use cpu.h instead.
+#endif
+
 #include "vm/allocation.h"
 #include "vm/simulator.h"
 
diff --git a/runtime/vm/cpu_arm64.h b/runtime/vm/cpu_arm64.h
index 25481cb..5fa7b2e 100644
--- a/runtime/vm/cpu_arm64.h
+++ b/runtime/vm/cpu_arm64.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_CPU_ARM64_H_
 #define RUNTIME_VM_CPU_ARM64_H_
 
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_arm64.h directly; use cpu.h instead.
+#endif
+
 #include "vm/allocation.h"
 #include "vm/simulator.h"
 
diff --git a/runtime/vm/cpu_dbc.h b/runtime/vm/cpu_dbc.h
index 08a4a83..5e0064b 100644
--- a/runtime/vm/cpu_dbc.h
+++ b/runtime/vm/cpu_dbc.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_CPU_DBC_H_
 #define RUNTIME_VM_CPU_DBC_H_
 
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_dbc.h directly; use cpu.h instead.
+#endif
+
 #include "vm/allocation.h"
 #include "vm/simulator.h"
 
diff --git a/runtime/vm/cpu_ia32.h b/runtime/vm/cpu_ia32.h
index d486327..a740fb5 100644
--- a/runtime/vm/cpu_ia32.h
+++ b/runtime/vm/cpu_ia32.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_CPU_IA32_H_
 #define RUNTIME_VM_CPU_IA32_H_
 
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_ia32.h directly; use cpu.h instead.
+#endif
+
 #include "vm/allocation.h"
 #include "vm/flags.h"
 
diff --git a/runtime/vm/cpu_x64.h b/runtime/vm/cpu_x64.h
index 716c5880..e87d2d5 100644
--- a/runtime/vm/cpu_x64.h
+++ b/runtime/vm/cpu_x64.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_CPU_X64_H_
 #define RUNTIME_VM_CPU_X64_H_
 
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_x64.h directly; use cpu.h instead.
+#endif
+
 #include "vm/allocation.h"
 #include "vm/flags.h"
 
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index cf87025..a9c024d 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -242,7 +242,7 @@
   EXPECT_VALID(toString);
   const char* c_str = NULL;
   EXPECT_VALID(Dart_StringToCString(toString, &c_str));
-  if (saved_echo) {
+  if (saved_echo != nullptr) {
     free(saved_echo);
   }
   saved_echo = strdup(c_str);
@@ -333,7 +333,7 @@
 
   OS::PrintErr("-- Starting event loop --\n");
   Event* event = event_queue->Get();
-  while (event) {
+  while (event != nullptr) {
     event->Process();
     delete event;
     event = event_queue->Get();
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index cc408ee..59f903a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -648,7 +648,7 @@
   // Initialize the new isolate.
   Thread* T = Thread::Current();
   Isolate* I = T->isolate();
-#if defined(SUPPORT_TIMLINE)
+#if defined(SUPPORT_TIMELINE)
   TimelineDurationScope tds(T, Timeline::GetIsolateStream(),
                             "InitializeIsolate");
   tds.SetNumArguments(1);
@@ -859,6 +859,14 @@
 #else
 #error What architecture?
 #endif
+  } else {
+#if defined(ARCH_IS_32_BIT)
+    buffer.AddString(" 32-bit");
+#elif defined(ARCH_IS_64_BIT)
+    buffer.AddString(" 64-bit");
+#else
+#error What word size?
+#endif
   }
 
   if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index fc9608a..4b259aa 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1643,10 +1643,6 @@
   DARTSCOPE(Thread::Current());
   API_TIMELINE_DURATION(T);
   Isolate* I = T->isolate();
-  if (!FLAG_load_deferred_eagerly) {
-    return Api::NewError(
-        "Creating full snapshots requires --load_deferred_eagerly");
-  }
   if (vm_snapshot_data_buffer != NULL && vm_snapshot_data_size == NULL) {
     RETURN_NULL_ERROR(vm_snapshot_data_size);
   }
@@ -1670,10 +1666,21 @@
 
   Symbols::Compact();
 
+  uint8_t* vm_snapshot_instruction_buffer = nullptr;
+  BlobImageWriter vm_image_writer(T, &vm_snapshot_instruction_buffer,
+                                  ApiReallocate, 2 * MB /* initial_size */,
+                                  /*shared_objects=*/nullptr,
+                                  /*shared_instructions=*/nullptr,
+                                  /*reused_instructions=*/nullptr);
+  uint8_t* isolate_snapshot_instruction_buffer = nullptr;
+  BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instruction_buffer,
+                                       ApiReallocate, 2 * MB /* initial_size */,
+                                       /*shared_objects=*/nullptr,
+                                       /*shared_instructions=*/nullptr,
+                                       /*reused_instructions=*/nullptr);
   FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
                             isolate_snapshot_data_buffer, ApiReallocate,
-                            NULL /* vm_image_writer */,
-                            NULL /* isolate_image_writer */);
+                            &vm_image_writer, &isolate_image_writer);
   writer.WriteFullSnapshot();
   if (vm_snapshot_data_buffer != NULL) {
     *vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
@@ -5392,7 +5399,6 @@
 DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library_in,
                                                 Dart_Handle error_in) {
   DARTSCOPE(Thread::Current());
-  Isolate* I = T->isolate();
 
   const Library& lib = Api::UnwrapLibraryHandle(Z, library_in);
   if (lib.IsNull()) {
@@ -5404,15 +5410,6 @@
   }
   CHECK_CALLBACK_STATE(T);
 
-  const GrowableObjectArray& pending_deferred_loads =
-      GrowableObjectArray::Handle(Z,
-                                  I->object_store()->pending_deferred_loads());
-  for (intptr_t i = 0; i < pending_deferred_loads.Length(); i++) {
-    if (pending_deferred_loads.At(i) == lib.raw()) {
-      lib.SetLoadError(err);
-      return Api::Null();
-    }
-  }
   return error_in;
 }
 
@@ -5503,9 +5500,6 @@
   // instead of freelists.
   BumpAllocateScope bump_allocate_scope(T);
 
-  // TODO(hausner): move the remaining code below (finalization and
-  // invoking of _completeDeferredLoads) into Isolate::DoneLoading().
-
   // Finalize all classes if needed.
   Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (Api::IsError(state)) {
@@ -5534,22 +5528,6 @@
   }
 #endif
 
-  if (complete_futures) {
-    const Library& corelib = Library::Handle(Z, Library::CoreLibrary());
-    const String& function_name =
-        String::Handle(Z, String::New("_completeDeferredLoads"));
-    const Function& function =
-        Function::Handle(Z, corelib.LookupFunctionAllowPrivate(function_name));
-    ASSERT(!function.IsNull());
-    const Array& args = Array::empty_array();
-
-    const Object& res =
-        Object::Handle(Z, DartEntry::InvokeFunction(function, args));
-    I->object_store()->clear_pending_deferred_loads();
-    if (res.IsError() || res.IsUnhandledException()) {
-      return Api::NewHandle(T, res.raw());
-    }
-  }
   return Api::Success();
 }
 
@@ -6160,7 +6138,6 @@
         "Isolate is not precompiled. "
         "Did you forget to call Dart_Precompile?");
   }
-  ASSERT(FLAG_load_deferred_eagerly);
   CHECK_NULL(callback);
 
   TIMELINE_DURATION(T, Isolate, "WriteAppAOTSnapshot");
@@ -6296,7 +6273,6 @@
         "Isolate is not precompiled. "
         "Did you forget to call Dart_Precompile?");
   }
-  ASSERT(FLAG_load_deferred_eagerly);
   CHECK_NULL(vm_snapshot_data_buffer);
   CHECK_NULL(vm_snapshot_data_size);
   CHECK_NULL(vm_snapshot_instructions_buffer);
@@ -6400,10 +6376,6 @@
   DARTSCOPE(Thread::Current());
   API_TIMELINE_DURATION(T);
   Isolate* I = T->isolate();
-  if (!FLAG_load_deferred_eagerly) {
-    return Api::NewError(
-        "Creating full snapshots requires --load_deferred_eagerly");
-  }
   CHECK_NULL(vm_snapshot_data_buffer);
   CHECK_NULL(vm_snapshot_data_size);
   CHECK_NULL(vm_snapshot_instructions_buffer);
@@ -6463,10 +6435,6 @@
   DARTSCOPE(Thread::Current());
   API_TIMELINE_DURATION(T);
   Isolate* I = T->isolate();
-  if (!FLAG_load_deferred_eagerly) {
-    return Api::NewError(
-        "Creating full snapshots requires --load_deferred_eagerly");
-  }
   CHECK_NULL(isolate_snapshot_data_buffer);
   CHECK_NULL(isolate_snapshot_data_size);
   CHECK_NULL(isolate_snapshot_instructions_buffer);
@@ -6479,7 +6447,7 @@
   BackgroundCompiler::Stop(I);
   DropRegExpMatchCode(Z);
 
-  if (reused_instructions) {
+  if (reused_instructions != nullptr) {
     DropCodeWithoutReusableInstructions(reused_instructions);
   }
   ProgramVisitor::Dedup();
@@ -6506,7 +6474,7 @@
   *isolate_snapshot_instructions_size =
       isolate_image_writer.InstructionsBlobSize();
 
-  if (reused_instructions) {
+  if (reused_instructions != nullptr) {
     *isolate_snapshot_instructions_buffer = NULL;
   }
 
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index bf716b7..5d444dc 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -4509,9 +4509,9 @@
   }
   const char* function_name = obj.ToCString();
   ASSERT(function_name != NULL);
-  if (!strcmp(function_name, "TestNativeFieldsAccess_init")) {
+  if (strcmp(function_name, "TestNativeFieldsAccess_init") == 0) {
     return reinterpret_cast<Dart_NativeFunction>(&TestNativeFieldsAccess_init);
-  } else if (!strcmp(function_name, "TestNativeFieldsAccess_access")) {
+  } else if (strcmp(function_name, "TestNativeFieldsAccess_access") == 0) {
     return reinterpret_cast<Dart_NativeFunction>(
         &TestNativeFieldsAccess_access);
   } else {
@@ -5754,9 +5754,9 @@
   *auto_scope_setup = true;
   const char* function_name = obj.ToCString();
   ASSERT(function_name != NULL);
-  if (!strcmp(function_name, "NativeArgument_Create")) {
+  if (strcmp(function_name, "NativeArgument_Create") == 0) {
     return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCreate);
-  } else if (!strcmp(function_name, "NativeArgument_Access")) {
+  } else if (strcmp(function_name, "NativeArgument_Access") == 0) {
     return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentAccess);
   }
   return NULL;
@@ -6958,13 +6958,13 @@
   const char* kNativeFoo2 = "NativeFoo2";
   const char* kNativeFoo3 = "NativeFoo3";
   const char* kNativeFoo4 = "NativeFoo4";
-  if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
+  if (strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1)) == 0) {
     return &NativeFoo1;
-  } else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
+  } else if (strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2)) == 0) {
     return &NativeFoo2;
-  } else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
+  } else if (strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3)) == 0) {
     return &NativeFoo3;
-  } else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
+  } else if (strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4)) == 0) {
     return &NativeFoo4;
   } else {
     UNREACHABLE();
@@ -7098,13 +7098,13 @@
   const char* kNativeFoo2 = "StaticNativeFoo2";
   const char* kNativeFoo3 = "StaticNativeFoo3";
   const char* kNativeFoo4 = "StaticNativeFoo4";
-  if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
+  if (strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1)) == 0) {
     return &StaticNativeFoo1;
-  } else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
+  } else if (strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2)) == 0) {
     return &StaticNativeFoo2;
-  } else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
+  } else if (strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3)) == 0) {
     return &StaticNativeFoo3;
-  } else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
+  } else if (strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4)) == 0) {
     return &StaticNativeFoo4;
   } else {
     UNREACHABLE();
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index ee4aa1d..e598ded 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include <memory>
+
 #include "vm/dart_api_message.h"
 #include "platform/unicode.h"
 #include "vm/object.h"
@@ -557,29 +559,43 @@
       return object;
     }
 
-#define READ_TYPED_DATA_HEADER(type)                                           \
-  intptr_t len = ReadSmiValue();                                               \
-  Dart_CObject* object =                                                       \
-      AllocateDartCObjectTypedData(Dart_TypedData_k##type, len);               \
-  AddBackRef(object_id, object, kIsDeserialized);
-
-#define READ_TYPED_DATA(type, ctype)                                           \
+#define READ_TYPED_DATA(tname, ctype)                                          \
   {                                                                            \
-    READ_TYPED_DATA_HEADER(type);                                              \
-    uint8_t* p =                                                               \
-        reinterpret_cast<uint8_t*>(object->value.as_typed_data.values);        \
-    ReadBytes(p, len * sizeof(ctype));                                         \
+    intptr_t len = ReadSmiValue();                                             \
+    auto type = Dart_TypedData_k##tname;                                       \
+    intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len;            \
+    Dart_CObject* object =                                                     \
+        reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject)));      \
+    ASSERT(object != NULL);                                                    \
+    object->type = Dart_CObject_kTypedData;                                    \
+    object->value.as_typed_data.type = type;                                   \
+    object->value.as_typed_data.length = length_in_bytes;                      \
+    if (len > 0) {                                                             \
+      Align(Zone::kAlignment);                                                 \
+      object->value.as_typed_data.values =                                     \
+          const_cast<uint8_t*>(CurrentBufferAddress());                        \
+      Advance(length_in_bytes);                                                \
+    } else {                                                                   \
+      object->value.as_typed_data.values = NULL;                               \
+    }                                                                          \
+    AddBackRef(object_id, object, kIsDeserialized);                            \
     return object;                                                             \
   }
 
-#define READ_EXTERNAL_TYPED_DATA(type, ctype)                                  \
+#define READ_EXTERNAL_TYPED_DATA(tname, ctype)                                 \
   {                                                                            \
-    READ_TYPED_DATA_HEADER(type);                                              \
-    uint8_t* p =                                                               \
-        reinterpret_cast<uint8_t*>(object->value.as_typed_data.values);        \
-    FinalizableData finalizable_data = finalizable_data_->Take();              \
-    memmove(p, finalizable_data.data, len * sizeof(ctype));                    \
-    finalizable_data.callback(NULL, NULL, finalizable_data.peer);              \
+    intptr_t len = ReadSmiValue();                                             \
+    auto type = Dart_TypedData_k##tname;                                       \
+    intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len;            \
+    Dart_CObject* object =                                                     \
+        reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject)));      \
+    ASSERT(object != NULL);                                                    \
+    object->type = Dart_CObject_kTypedData;                                    \
+    object->value.as_typed_data.type = type;                                   \
+    object->value.as_typed_data.length = length_in_bytes;                      \
+    object->value.as_typed_data.values =                                       \
+        reinterpret_cast<uint8_t*>(finalizable_data_->Get().data);             \
+    AddBackRef(object_id, object, kIsDeserialized);                            \
     return object;                                                             \
   }
 
@@ -635,7 +651,6 @@
 #undef READ_TYPED_DATA
 #undef READ_EXTERNAL_TYPED_DATA
 #undef READ_TYPED_DATA_VIEW
-#undef READ_TYPED_DATA_HEADER
 
     case kGrowableObjectArrayCid: {
       // A GrowableObjectArray is serialized as its type arguments and
@@ -1069,11 +1084,13 @@
         case kTypedDataInt8ArrayCid:
         case kTypedDataUint8ArrayCid: {
           uint8_t* bytes = object->value.as_typed_data.values;
+          Align(Zone::kAlignment);
           WriteBytes(bytes, len);
           break;
         }
         case kTypedDataUint32ArrayCid: {
           uint8_t* bytes = object->value.as_typed_data.values;
+          Align(Zone::kAlignment);
           WriteBytes(bytes, len * sizeof(uint32_t));
           break;
         }
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 13bd393..da4c450 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -89,7 +89,7 @@
   const uint8_t* AddressOfCurrentPosition() const { return current_; }
 
   void Advance(intptr_t value) {
-    ASSERT((end_ - current_) > value);
+    ASSERT((end_ - current_) >= value);
     current_ = current_ + value;
   }
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 81d31da..0dd231a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -841,6 +841,8 @@
     return Object::null();
   }
   GetVarDescriptors();
+  intptr_t var_ctxt_level = -1;
+  intptr_t ctxt_slot = -1;
   intptr_t var_desc_len = var_descriptors_.Length();
   for (intptr_t i = 0; i < var_desc_len; i++) {
     RawLocalVarDescriptors::VarInfo var_info;
@@ -855,21 +857,29 @@
         return GetStackVar(variable_index);
       } else {
         ASSERT(kind == RawLocalVarDescriptors::kContextVar);
-        if (!live_frame_) {
-          ASSERT(!ctx_.IsNull());
-          // Compiled code uses relative context levels, i.e. the frame context
-          // level is always 0 on entry.
-          // Bytecode uses absolute context levels, i.e. the frame context level
-          // on entry must be calculated.
-          const intptr_t frame_ctx_level =
-              function().is_declared_in_bytecode() ? ctx_.GetLevel() : 0;
-          return GetRelativeContextVar(var_info.scope_id,
-                                       variable_index.value(), frame_ctx_level);
+        // Variable descriptors constructed from bytecode have all variables of
+        // enclosing functions, even shadowed by the current function.
+        // Pick the variable with the highest context level.
+        if (var_info.scope_id > var_ctxt_level) {
+          var_ctxt_level = var_info.scope_id;
+          ctxt_slot = variable_index.value();
         }
-        return GetContextVar(var_info.scope_id, variable_index.value());
       }
     }
   }
+  if (var_ctxt_level >= 0) {
+    if (!live_frame_) {
+      ASSERT(!ctx_.IsNull());
+      // Compiled code uses relative context levels, i.e. the frame context
+      // level is always 0 on entry.
+      // Bytecode uses absolute context levels, i.e. the frame context level
+      // on entry must be calculated.
+      const intptr_t frame_ctx_level =
+          function().is_declared_in_bytecode() ? ctx_.GetLevel() : 0;
+      return GetRelativeContextVar(var_ctxt_level, ctxt_slot, frame_ctx_level);
+    }
+    return GetContextVar(var_ctxt_level, ctxt_slot);
+  }
   return Object::null();
 }
 
@@ -987,6 +997,8 @@
 
 intptr_t ActivationFrame::GetAwaitJumpVariable() {
   GetVarDescriptors();
+  intptr_t var_ctxt_level = -1;
+  intptr_t ctxt_slot = -1;
   intptr_t var_desc_len = var_descriptors_.Length();
   intptr_t await_jump_var = -1;
   for (intptr_t i = 0; i < var_desc_len; i++) {
@@ -998,16 +1010,18 @@
       ASSERT(!ctx_.IsNull());
       // Variable descriptors constructed from bytecode have all variables of
       // enclosing functions, even shadowed by the current function.
-      // Check context level in order to pick correct :await_jump_var variable.
-      if (function().is_declared_in_bytecode() &&
-          (ctx_.GetLevel() != var_info.scope_id)) {
-        continue;
+      // Pick the :await_jump_var variable with the highest context level.
+      if (var_info.scope_id > var_ctxt_level) {
+        var_ctxt_level = var_info.scope_id;
+        ctxt_slot = var_info.index();
       }
-      Object& await_jump_index = Object::Handle(ctx_.At(var_info.index()));
-      ASSERT(await_jump_index.IsSmi());
-      await_jump_var = Smi::Cast(await_jump_index).Value();
     }
   }
+  if (var_ctxt_level >= 0) {
+    Object& await_jump_index = Object::Handle(ctx_.At(ctxt_slot));
+    ASSERT(await_jump_index.IsSmi());
+    await_jump_var = Smi::Cast(await_jump_index).Value();
+  }
   return await_jump_var;
 }
 
@@ -1170,6 +1184,10 @@
     const Instance& exc_obj) const {
   for (intptr_t frame_index = 0; frame_index < Length(); frame_index++) {
     ActivationFrame* frame = FrameAt(frame_index);
+    if (FLAG_trace_debugger_stacktrace) {
+      OS::PrintErr("GetHandlerFrame: #%04" Pd " %s", frame_index,
+                   frame->ToCString());
+    }
     if (frame->HandlesException(exc_obj)) {
       return frame;
     }
@@ -1592,6 +1610,10 @@
 }
 
 const char* ActivationFrame::ToCString() {
+  if (function().IsNull()) {
+    return Thread::Current()->zone()->PrintToString("[ Frame kind: %s]\n",
+                                                    KindToCString(kind_));
+  }
   const String& url = String::Handle(SourceUrl());
   intptr_t line = LineNumber();
   const char* func_name = Debugger::QualifiedFunctionName(function());
@@ -1616,7 +1638,7 @@
         "\turl = %s\n"
         "\tline = %" Pd
         "\n"
-        "\tcontext = %s\n",
+        "\tcontext = %s]\n",
         IsInterpreted() ? "bytecode" : "code", func_name, url.ToCString(), line,
         ctx_.ToCString());
   }
@@ -1945,7 +1967,7 @@
   ActivationFrame* top_frame = TopDartFrame();
   if (!IsAtAsyncJump(top_frame)) {
     // Not at an async operation.
-    if (error) {
+    if (error != nullptr) {
       *error = "Isolate must be paused at an async suspension point";
     }
     return false;
@@ -1957,7 +1979,7 @@
   Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true);
   if (bpt == NULL) {
     // Unable to set the breakpoint.
-    if (error) {
+    if (error != nullptr) {
       *error = "Unable to set breakpoint at async suspension point";
     }
     return false;
@@ -1968,7 +1990,7 @@
 bool Debugger::SetResumeAction(ResumeAction action,
                                intptr_t frame_index,
                                const char** error) {
-  if (error) {
+  if (error != nullptr) {
     *error = NULL;
   }
   resume_frame_index_ = -1;
@@ -2149,7 +2171,7 @@
 RawArray* Debugger::DeoptimizeToArray(Thread* thread,
                                       StackFrame* frame,
                                       const Code& code) {
-  ASSERT(code.is_optimized());
+  ASSERT(code.is_optimized() && !code.is_force_optimized());
   Isolate* isolate = thread->isolate();
   // Create the DeoptContext for this deoptimization.
   DeoptContext* deopt_context =
@@ -2223,6 +2245,16 @@
                                 Array* deopt_frame) {
 #if !defined(DART_PRECOMPILED_RUNTIME)
   if (code->is_optimized()) {
+    if (code->is_force_optimized()) {
+      if (FLAG_trace_debugger_stacktrace) {
+        const Function& function = Function::Handle(zone, code->function());
+        ASSERT(!function.IsNull());
+        OS::PrintErr(
+            "CollectStackTrace: skipping force-optimized function: %s\n",
+            function.ToFullyQualifiedCString());
+      }
+      return;  // Skip frame of force-optimized (and non-debuggable) function.
+    }
     // TODO(rmacnak): Use CodeSourceMap
     *deopt_frame = DeoptimizeToArray(thread, frame, *code);
     for (InlinedFunctionsIterator it(*code, frame->pc()); !it.Done();
@@ -2445,6 +2477,18 @@
       } else {
         code = frame->LookupDartCode();
         if (code.is_optimized()) {
+          if (code.is_force_optimized()) {
+            if (FLAG_trace_debugger_stacktrace) {
+              function = code.function();
+              ASSERT(!function.IsNull());
+              OS::PrintErr(
+                  "CollectAwaiterReturnStackTrace: "
+                  "skipping force-optimized function: %s\n",
+                  function.ToFullyQualifiedCString());
+            }
+            // Skip frame of force-optimized (and non-debuggable) function.
+            continue;
+          }
           deopt_frame = DeoptimizeToArray(thread, frame, code);
           bool found_async_awaiter = false;
           bool abort_attempt_to_navigate_through_sync_async = false;
@@ -2469,8 +2513,8 @@
             if (FLAG_trace_debugger_stacktrace) {
               ASSERT(!function.IsNull());
               OS::PrintErr(
-                  "CollectAwaiterReturnStackTrace: visiting inlined function: "
-                  "%s\n",
+                  "CollectAwaiterReturnStackTrace: "
+                  "visiting inlined function: %s\n ",
                   function.ToFullyQualifiedCString());
             }
             intptr_t deopt_frame_offset = it.GetDeoptFpOffset();
@@ -2982,7 +3026,8 @@
                   TokenPosition::kMaxSource;
               while (iter2.MoveNext()) {
                 const TokenPosition next = iter2.TokenPos();
-                if (next < next_closest_token_position && next > pos) {
+                if (next.IsReal() && next < next_closest_token_position &&
+                    next > pos) {
                   next_closest_token_position = next;
                 }
               }
@@ -3154,9 +3199,13 @@
             pc = bytecode.GetDebugCheckedOpcodeReturnAddress(pc_offset,
                                                              iter.PcOffset());
             pc_offset = kUwordMax;
-            // TODO(regis): We may want to find all PCs for a token position,
-            // e.g. in the case of duplicated bytecode in finally clauses.
-            break;
+            if (pc != 0) {
+              // TODO(regis): We may want to find all PCs for a token position,
+              // e.g. in the case of duplicated bytecode in finally clauses.
+              break;
+            }
+            // This range does not contain a 'debug checked' opcode or the
+            // first DebugCheck opcode of the function is not reached yet.
           }
           if (iter.TokenPos() == loc->token_pos_) {
             pc_offset = iter.PcOffset();
@@ -3177,6 +3226,12 @@
       if (code_bpt == NULL) {
         // No code breakpoint for this code exists; create one.
         code_bpt = new CodeBreakpoint(bytecode, loc->token_pos_, pc);
+        if (FLAG_verbose_debug) {
+          OS::PrintErr("Setting bytecode breakpoint at pos %s pc %#" Px
+                       " offset %#" Px "\n",
+                       loc->token_pos_.ToCString(), pc,
+                       pc - bytecode.PayloadStart());
+        }
         RegisterCodeBreakpoint(code_bpt);
       }
       code_bpt->set_bpt_location(loc);
@@ -3210,6 +3265,12 @@
         // No code breakpoint for this code exists; create one.
         code_bpt =
             new CodeBreakpoint(code, loc->token_pos_, lowest_pc, lowest_kind);
+        if (FLAG_verbose_debug) {
+          OS::PrintErr("Setting code breakpoint at pos %s pc %#" Px
+                       " offset %#" Px "\n",
+                       loc->token_pos_.ToCString(), lowest_pc,
+                       lowest_pc - code.PayloadStart());
+        }
         RegisterCodeBreakpoint(code_bpt);
       }
       code_bpt->set_bpt_location(loc);
@@ -3493,10 +3554,10 @@
     intptr_t line_number;
     intptr_t column_number;
     script.GetTokenLocation(breakpoint_pos, &line_number, &column_number);
-    OS::PrintErr(
-        "Resolved BP for "
-        "function '%s' at line %" Pd " col %" Pd "\n",
-        func.ToFullyQualifiedCString(), line_number, column_number);
+    OS::PrintErr("Resolved %s breakpoint for function '%s' at line %" Pd
+                 " col %" Pd "\n",
+                 in_bytecode ? "bytecode" : "code",
+                 func.ToFullyQualifiedCString(), line_number, column_number);
   }
   return loc;
 }
@@ -3933,6 +3994,11 @@
           // Step out to the awaiter.
           ASSERT(async_op.IsClosure());
           AsyncStepInto(Closure::Cast(async_op));
+          if (FLAG_verbose_debug) {
+            OS::PrintErr("HandleSteppingRequest- kContinue to async_op %s\n",
+                         Function::Handle(Closure::Cast(async_op).function())
+                             .ToFullyQualifiedCString());
+          }
           return;
         }
       }
@@ -4007,7 +4073,7 @@
   DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace();
   intptr_t num_frames = stack->Length();
   if (frame_index < 1 || frame_index >= num_frames) {
-    if (error) {
+    if (error != nullptr) {
       *error = Thread::Current()->zone()->PrintToString(
           "Frame must be in bounds [1..%" Pd
           "]: "
@@ -4703,8 +4769,8 @@
           } else {
             if (FLAG_verbose_debug) {
               OS::PrintErr(
-                  "Pending BP remains unresolved in inner bytecode function "
-                  "'%s'\n",
+                  "Pending breakpoint remains unresolved in "
+                  "inner bytecode function '%s'\n",
                   inner_function.ToFullyQualifiedCString());
             }
           }
@@ -4716,7 +4782,8 @@
           ASSERT(!inner_function.HasCode());
           if (FLAG_verbose_debug) {
             OS::PrintErr(
-                "Pending BP remains unresolved in inner function '%s'\n",
+                "Pending breakpoint remains unresolved in "
+                "inner function '%s'\n",
                 inner_function.ToFullyQualifiedCString());
           }
           continue;
@@ -4730,6 +4797,8 @@
       // There is no local function within func that contains the
       // breakpoint token position. Resolve the breakpoint if necessary
       // and set the code breakpoints.
+      const bool resolved_in_bytecode =
+          !bytecode_loaded && loc->IsResolved(/* in_bytecode = */ true);
       if (!loc->IsResolved(bytecode_loaded)) {
         // Resolve source breakpoint in the newly compiled function.
         TokenPosition bp_pos = ResolveBreakpointPos(
@@ -4738,7 +4807,7 @@
         if (!bp_pos.IsDebugPause()) {
           if (FLAG_verbose_debug) {
             OS::PrintErr("Failed resolving breakpoint for function '%s'\n",
-                         String::Handle(func.name()).ToCString());
+                         func.ToFullyQualifiedCString());
           }
           continue;
         }
@@ -4749,15 +4818,18 @@
         while (bpt != NULL) {
           if (FLAG_verbose_debug) {
             OS::PrintErr(
-                "Resolved BP %" Pd
-                " to pos %s, "
-                "function '%s' (requested range %s-%s, "
+                "Resolved breakpoint %" Pd
+                " to pos %s, function '%s' (requested range %s-%s, "
                 "requested col %" Pd ")\n",
                 bpt->id(), loc->token_pos().ToCString(),
                 func.ToFullyQualifiedCString(), requested_pos.ToCString(),
                 requested_end_pos.ToCString(), loc->requested_column_number());
           }
-          SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+          // Do not signal resolution in code if already signaled resolution
+          // in bytecode.
+          if (!resolved_in_bytecode) {
+            SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+          }
           bpt = bpt->next();
         }
       }
@@ -4767,7 +4839,7 @@
         while (bpt != NULL) {
           OS::PrintErr("Setting breakpoint %" Pd " for %s '%s'\n", bpt->id(),
                        func.IsClosureFunction() ? "closure" : "function",
-                       String::Handle(func.name()).ToCString());
+                       func.ToFullyQualifiedCString());
           bpt = bpt->next();
         }
       }
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 38a1d15..6306029 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -82,8 +82,6 @@
 static const intptr_t kElfSymbolHashTableEntrySize = 4;
 #endif
 
-static const intptr_t kPageSize = 4096;
-
 class Section : public ZoneAllocated {
  public:
   Section() {}
@@ -115,23 +113,34 @@
  public:
   ProgramBits(bool allocate,
               bool executable,
+              bool writable,
               const uint8_t* bytes,
-              intptr_t size) {
+              intptr_t filesz,
+              intptr_t memsz = -1) {
+    if (memsz == -1) memsz = filesz;
+
     section_type = SHT_PROGBITS;
     if (allocate) {
       section_flags = SHF_ALLOC;
       if (executable) section_flags |= SHF_EXECINSTR;
+      if (writable) section_flags |= SHF_WRITE;
 
       segment_type = PT_LOAD;
       segment_flags = PF_R;
       if (executable) segment_flags |= PF_X;
+      if (writable) segment_flags |= PF_W;
     }
 
     bytes_ = bytes;
-    file_size = memory_size = size;
+    file_size = filesz;
+    memory_size = memsz;
   }
 
-  void Write(Elf* stream) { stream->WriteBytes(bytes_, memory_size); }
+  void Write(Elf* stream) {
+    if (bytes_ != nullptr) {
+      stream->WriteBytes(bytes_, file_size);
+    }
+  }
 
   const uint8_t* bytes_;
 };
@@ -247,7 +256,7 @@
 
 static uint32_t ElfHash(const unsigned char* name) {
   uint32_t h = 0;
-  while (*name) {
+  while (*name != '\0') {
     h = (h << 4) + *name++;
     uint32_t g = h & 0xf0000000;
     h ^= g;
@@ -371,7 +380,7 @@
 // Elf::segments_.
 static const intptr_t kNumImplicitSegments = 3;
 
-static const intptr_t kProgramTableSegmentSize = kPageSize;
+static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
 
 Elf::Elf(Zone* zone, StreamingWriteStream* stream)
     : zone_(zone), stream_(stream), memory_offset_(0) {
@@ -415,7 +424,7 @@
 }
 
 intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
-  ProgramBits* image = new (zone_) ProgramBits(true, true, bytes, size);
+  ProgramBits* image = new (zone_) ProgramBits(true, true, false, bytes, size);
   image->section_name = shstrtab_->AddString(".text");
   AddSection(image);
   AddSegment(image);
@@ -434,8 +443,29 @@
   return symbol->offset;
 }
 
+intptr_t Elf::AddBSSData(const char* name, intptr_t size) {
+  ProgramBits* image = new (zone_)
+      ProgramBits(true, false, true, nullptr, /*filesz=*/0, /*memsz=*/size);
+  image->section_name = shstrtab_->AddString(".bss");
+  AddSection(image);
+  AddSegment(image);
+
+  Symbol* symbol = new (zone_) Symbol();
+  symbol->cstr = name;
+  symbol->name = symstrtab_->AddString(name);
+  symbol->info = (STB_GLOBAL << 4) | STT_OBJECT;
+  symbol->section = image->section_index;
+  // For shared libraries, this is the offset from the DSO base. For static
+  // libraries, this is section relative.
+  symbol->offset = image->memory_offset;
+  symbol->size = size;
+  symtab_->AddSymbol(symbol);
+
+  return symbol->offset;
+}
+
 intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
-  ProgramBits* image = new (zone_) ProgramBits(true, false, bytes, size);
+  ProgramBits* image = new (zone_) ProgramBits(true, false, false, bytes, size);
   image->section_name = shstrtab_->AddString(".rodata");
   AddSection(image);
   AddSegment(image);
@@ -455,7 +485,8 @@
 }
 
 void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
-  ProgramBits* image = new (zone_) ProgramBits(false, false, bytes, size);
+  ProgramBits* image =
+      new (zone_) ProgramBits(false, false, false, bytes, size);
   image->section_name = shstrtab_->AddString(name);
   AddSection(image);
 }
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index d6d63b7..882c917 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -23,9 +23,12 @@
  public:
   Elf(Zone* zone, StreamingWriteStream* stream);
 
+  static const intptr_t kPageSize = 4096;
+
   intptr_t NextMemoryOffset();
   intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
   intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
+  intptr_t AddBSSData(const char* name, intptr_t size);
   void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
 
   void Finalize();
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index a341cad..aa3fd63 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -515,12 +515,16 @@
     {
       DartFrameIterator frames(thread,
                                StackFrameIterator::kNoCrossThreadIteration);
-      StackFrame* frame = frames.NextFrame();
-      while ((frame != NULL) && (frame->fp() < frame_pointer)) {
+      for (StackFrame* frame = frames.NextFrame(); frame != nullptr;
+           frame = frames.NextFrame()) {
+        if (frame->is_interpreted()) {
+          continue;
+        } else if (frame->fp() >= frame_pointer) {
+          break;
+        }
         if (frame->IsMarkedForLazyDeopt()) {
           frame->UnmarkForLazyDeopt();
         }
-        frame = frames.NextFrame();
       }
     }
 
diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc
index fe090d6..722ffef 100644
--- a/runtime/vm/exceptions_test.cc
+++ b/runtime/vm/exceptions_test.cc
@@ -76,7 +76,7 @@
   int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
   for (int i = 0; i < num_entries; i++) {
     struct NativeEntries* entry = &(BuiltinEntries[i]);
-    if (!strcmp(function_name, entry->name_) &&
+    if ((strcmp(function_name, entry->name_) == 0) &&
         (argument_count == entry->argument_count_)) {
       return reinterpret_cast<Dart_NativeFunction>(entry->function_);
     }
diff --git a/runtime/vm/ffi_callback_trampolines.cc b/runtime/vm/ffi_callback_trampolines.cc
index 5516ddb..af987dc 100644
--- a/runtime/vm/ffi_callback_trampolines.cc
+++ b/runtime/vm/ffi_callback_trampolines.cc
@@ -14,7 +14,22 @@
 DECLARE_FLAG(bool, disassemble_stubs);
 
 #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
-uword NativeCallbackTrampolines::AllocateTrampoline() {
+uword NativeCallbackTrampolines::TrampolineForId(int32_t callback_id) {
+#if defined(DART_PRECOMPILER)
+  ASSERT(!Enabled());
+  UNREACHABLE();
+#else
+  const intptr_t trampolines_per_page = NumCallbackTrampolinesPerPage();
+  const intptr_t page_index = callback_id / trampolines_per_page;
+  const uword entry_point = trampoline_pages_[page_index]->start();
+
+  return entry_point +
+         (callback_id % trampolines_per_page) *
+             compiler::StubCodeCompiler::kNativeCallbackTrampolineSize;
+#endif
+}
+
+void NativeCallbackTrampolines::AllocateTrampoline() {
 #if defined(DART_PRECOMPILER)
   ASSERT(!Enabled());
   UNREACHABLE();
@@ -76,16 +91,11 @@
     }
 #endif
 
-    next_callback_trampoline_ = memory->start();
     trampolines_left_on_page_ = NumCallbackTrampolinesPerPage();
   }
 
   trampolines_left_on_page_--;
   next_callback_id_++;
-  const uword entrypoint = next_callback_trampoline_;
-  next_callback_trampoline_ +=
-      compiler::StubCodeCompiler::kNativeCallbackTrampolineSize;
-  return entrypoint;
 #endif  // defined(DART_PRECOMPILER)
 }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
diff --git a/runtime/vm/ffi_callback_trampolines.h b/runtime/vm/ffi_callback_trampolines.h
index 65c2a37ec..77822d5 100644
--- a/runtime/vm/ffi_callback_trampolines.h
+++ b/runtime/vm/ffi_callback_trampolines.h
@@ -57,11 +57,13 @@
 
   // Allocates a callback trampoline corresponding to the callback id
   // 'next_callback_id()'. Returns an entrypoint to the trampoline.
-  uword AllocateTrampoline();
+  void AllocateTrampoline();
+
+  // Get the entrypoint for a previously allocated callback ID.
+  uword TrampolineForId(int32_t callback_id);
 
  private:
   MallocGrowableArray<VirtualMemory*> trampoline_pages_;
-  uword next_callback_trampoline_ = 0;
   intptr_t trampolines_left_on_page_ = 0;
   intptr_t next_callback_id_ = 0;
 
diff --git a/runtime/vm/finalizable_data.h b/runtime/vm/finalizable_data.h
index df383d2..acea96c 100644
--- a/runtime/vm/finalizable_data.h
+++ b/runtime/vm/finalizable_data.h
@@ -20,10 +20,11 @@
 
 class MessageFinalizableData {
  public:
-  MessageFinalizableData() : records_(0), position_(0), external_size_(0) {}
+  MessageFinalizableData()
+      : records_(0), get_position_(0), take_position_(0), external_size_(0) {}
 
   ~MessageFinalizableData() {
-    for (intptr_t i = position_; i < records_.length(); i++) {
+    for (intptr_t i = take_position_; i < records_.length(); i++) {
       records_[i].callback(nullptr, nullptr, records_[i].peer);
     }
   }
@@ -46,13 +47,22 @@
     external_size_ += external_size;
   }
 
+  // Retrieve the next FinalizableData, but still run its finalizer when |this|
+  // is destroyed.
+  FinalizableData Get() {
+    ASSERT(get_position_ < records_.length());
+    return records_[get_position_++];
+  }
+
+  // Retrieve the next FinalizableData, and skip its finalizer when |this| is
+  // destroyed.
   FinalizableData Take() {
-    ASSERT(position_ < records_.length());
-    return records_[position_++];
+    ASSERT(take_position_ < records_.length());
+    return records_[take_position_++];
   }
 
   void SerializationSucceeded() {
-    for (intptr_t i = position_; i < records_.length(); i++) {
+    for (intptr_t i = 0; i < records_.length(); i++) {
       if (records_[i].successful_write_callback != nullptr) {
         records_[i].successful_write_callback(nullptr, nullptr,
                                               records_[i].peer);
@@ -64,7 +74,8 @@
 
  private:
   MallocGrowableArray<FinalizableData> records_;
-  intptr_t position_;
+  intptr_t get_position_;
+  intptr_t take_position_;
   intptr_t external_size_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageFinalizableData);
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index eb8434a..42d44cc 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -116,8 +116,6 @@
   P(interpret_irregexp, bool, USING_DBC, "Use irregexp bytecode interpreter")  \
   P(lazy_dispatchers, bool, true, "Generate dispatchers lazily")               \
   P(link_natives_lazily, bool, false, "Link native calls lazily")              \
-  C(load_deferred_eagerly, true, true, bool, false,                            \
-    "Load deferred libraries eagerly.")                                        \
   R(log_marker_tasks, false, bool, false,                                      \
     "Log debugging information for old gen GC marking tasks.")                 \
   P(marker_tasks, int, USING_MULTICORE ? 2 : 0,                                \
diff --git a/runtime/vm/frame_layout.h b/runtime/vm/frame_layout.h
index 3242353..4327050 100644
--- a/runtime/vm/frame_layout.h
+++ b/runtime/vm/frame_layout.h
@@ -5,6 +5,9 @@
 #ifndef RUNTIME_VM_FRAME_LAYOUT_H_
 #define RUNTIME_VM_FRAME_LAYOUT_H_
 
+#include "platform/assert.h"
+#include "platform/globals.h"
+
 // FrameLayout structure captures configuration specific properties of the
 // frame layout used by the runtime system and compiler.
 //
diff --git a/runtime/vm/gdb_helpers.cc b/runtime/vm/gdb_helpers.cc
index 44ba132..b32297c 100644
--- a/runtime/vm/gdb_helpers.cc
+++ b/runtime/vm/gdb_helpers.cc
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "lib/stacktrace.h"
+#include "vm/heap/safepoint.h"
 #include "vm/object.h"
 #include "vm/stack_frame.h"
 
@@ -39,12 +40,48 @@
                             Thread::Current(),
                             StackFrameIterator::kNoCrossThreadIteration);
   StackFrame* frame = frames.NextFrame();
-  while (frame != NULL) {
+  while (frame != nullptr) {
     OS::PrintErr("%s\n", frame->ToCString());
     frame = frames.NextFrame();
   }
 }
 
+#if !defined(TARGET_ARCH_DBC)
+// Like _printDartStackTrace, but works when stopped in generated code.
+// Must be called with the current fp, sp, and pc.
+DART_EXPORT
+void _printGeneratedStackTrace(uword fp, uword sp, uword pc) {
+  StackFrameIterator frames(fp, sp, pc, ValidationPolicy::kDontValidateFrames,
+                            Thread::Current(),
+                            StackFrameIterator::kNoCrossThreadIteration);
+  StackFrame* frame = frames.NextFrame();
+  while (frame != nullptr) {
+    OS::PrintErr("%s\n", frame->ToCString());
+    frame = frames.NextFrame();
+  }
+}
+
+// Like _printDartStackTrace, but works in the interpreter loop.
+// Must be called with the current interpreter fp, sp, and pc.
+// Note that sp[0] is not modified, but sp[1] will be trashed.
+DART_EXPORT
+void _printInterpreterStackTrace(RawObject** fp,
+                                 RawObject** sp,
+                                 const KBCInstr* pc) {
+  Thread* thread = Thread::Current();
+  sp[1] = Function::null();
+  sp[2] = Bytecode::null();
+  sp[3] = reinterpret_cast<RawObject*>(reinterpret_cast<uword>(pc));
+  sp[4] = reinterpret_cast<RawObject*>(fp);
+  RawObject** exit_fp = sp + 1 + kKBCDartFrameFixedSize;
+  thread->set_top_exit_frame_info(reinterpret_cast<uword>(exit_fp));
+  thread->set_execution_state(Thread::kThreadInVM);
+  _printDartStackTrace();
+  thread->set_execution_state(Thread::kThreadInGenerated);
+  thread->set_top_exit_frame_info(0);
+}
+#endif  // !defined(TARGET_ARCH_DBC)
+
 class PrintObjectPointersVisitor : public ObjectPointerVisitor {
  public:
   PrintObjectPointersVisitor() : ObjectPointerVisitor(Isolate::Current()) {}
@@ -64,7 +101,7 @@
                             Thread::Current(),
                             StackFrameIterator::kNoCrossThreadIteration);
   StackFrame* frame = frames.NextFrame();
-  while (frame != NULL) {
+  while (frame != nullptr) {
     OS::PrintErr("%s\n", frame->ToCString());
     frame->VisitObjectPointers(&visitor);
     frame = frames.NextFrame();
diff --git a/runtime/vm/hash.h b/runtime/vm/hash.h
index b4fc808..cbd4c83 100644
--- a/runtime/vm/hash.h
+++ b/runtime/vm/hash.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_HASH_H_
 #define RUNTIME_VM_HASH_H_
 
+#include "platform/globals.h"
+
 namespace dart {
 
 inline uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) {
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 4f2efda..04bfdd1 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_HASH_MAP_H_
 
 #include "vm/growable_array.h"  // For Malloc, EmptyBase
+#include "vm/hash.h"
 #include "vm/zone.h"
 
 namespace dart {
@@ -34,9 +35,19 @@
     allocator_->template Free<HashMapListElement>(lists_, lists_size_);
   }
 
+  // Assumes that no existing pair in the map has a key equal to [kv.key].
   void Insert(typename KeyValueTrait::Pair kv);
   bool Remove(typename KeyValueTrait::Key key);
 
+  // If a pair already exists in the map with an equal key, replace that pair
+  // with this one. Otherwise, insert the pair as a new entry.
+  //
+  // Note: Insert operates in constant time, while Update must walk the chained
+  // entries for a given hash value, checking keys for equality. However, if
+  // multiple value updates are needed for the same key, only using Update
+  // guarantees constant space usage whereas Insert does not.
+  void Update(typename KeyValueTrait::Pair kv);
+
   typename KeyValueTrait::Value LookupValue(
       typename KeyValueTrait::Key key) const;
 
@@ -286,6 +297,8 @@
       KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
 
   ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
+  // TODO(dartbug.com/38018): Add assert that Lookup returns nullptr for key.
+
   // Resizing when half of the hashtable is filled up.
   if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
   ASSERT(count_ < array_size_);
@@ -311,13 +324,31 @@
 }
 
 template <typename KeyValueTrait, typename B, typename Allocator>
+void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Update(
+    typename KeyValueTrait::Pair kv) {
+  const typename KeyValueTrait::Value kNoValue =
+      KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
+
+  ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
+  if (auto const old_kv = Lookup(KeyValueTrait::KeyOf(kv))) {
+    *old_kv = kv;
+  } else {
+    Insert(kv);
+  }
+}
+
+template <typename KeyValueTrait, typename B, typename Allocator>
 bool BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Remove(
     typename KeyValueTrait::Key key) {
+  const typename KeyValueTrait::Value kNoValue =
+      KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
+
   uword pos = Bound(static_cast<uword>(KeyValueTrait::Hashcode(key)));
 
   // Check to see if the first element in the bucket is the one we want to
   // remove.
-  if (KeyValueTrait::KeyOf(array_[pos].kv) == key) {
+  if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) return false;
+  if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) {
     if (array_[pos].next == kNil) {
       array_[pos] = HashMapListElement();
     } else {
@@ -341,7 +372,7 @@
 
   // Check the case where the second element in the bucket is the one to be
   // removed.
-  if (KeyValueTrait::KeyOf(lists_[current].kv) == key) {
+  if (KeyValueTrait::IsKeyEqual(lists_[current].kv, key)) {
     array_[pos].next = lists_[current].next;
     lists_[current] = HashMapListElement();
     lists_[current].next = free_list_head_;
@@ -353,7 +384,7 @@
   // Finally, iterate through the rest of the bucket to see if we can find the
   // entry that matches our key.
   intptr_t previous;
-  while (KeyValueTrait::KeyOf(lists_[current].kv) != key) {
+  while (!KeyValueTrait::IsKeyEqual(lists_[current].kv, key)) {
     previous = current;
     current = lists_[current].next;
 
@@ -459,6 +490,38 @@
 };
 
 template <typename V>
+class CStringKeyValueTrait : public RawPointerKeyValueTrait<const char, V> {
+ public:
+  typedef typename RawPointerKeyValueTrait<const char, V>::Key Key;
+  typedef typename RawPointerKeyValueTrait<const char, V>::Value Value;
+  typedef typename RawPointerKeyValueTrait<const char, V>::Pair Pair;
+
+  static intptr_t Hashcode(Key key) {
+    ASSERT(key != nullptr);
+    intptr_t hash = 0;
+    for (size_t i = 0; i < strlen(key); i++) {
+      hash = CombineHashes(hash, key[i]);
+    }
+    return FinalizeHash(hash, kBitsPerWord - 1);
+  }
+  static bool IsKeyEqual(Pair kv, Key key) {
+    ASSERT(kv.key != nullptr && key != nullptr);
+    return kv.key == key || strcmp(kv.key, key) == 0;
+  }
+};
+
+template <typename V>
+class CStringMap : public DirectChainedHashMap<CStringKeyValueTrait<V>> {
+ public:
+  CStringMap() : DirectChainedHashMap<CStringKeyValueTrait<V>>() {}
+  explicit CStringMap(Zone* zone)
+      : DirectChainedHashMap<CStringKeyValueTrait<V>>(zone) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CStringMap);
+};
+
+template <typename V>
 class IntKeyRawPointerValueTrait {
  public:
   typedef intptr_t Key;
diff --git a/runtime/vm/hash_map_test.cc b/runtime/vm/hash_map_test.cc
index 6a1e4f3..a040869 100644
--- a/runtime/vm/hash_map_test.cc
+++ b/runtime/vm/hash_map_test.cc
@@ -172,4 +172,132 @@
   EXPECT(sum == 15);
 }
 
+TEST_CASE(CStringMap) {
+  const char* const kConst1 = "test";
+  const char* const kConst2 = "test 2";
+
+  char* const str1 = OS::SCreate(nullptr, "%s", kConst1);
+  char* const str2 = OS::SCreate(nullptr, "%s", kConst2);
+  char* const str3 = OS::SCreate(nullptr, "%s", kConst1);
+
+  // Make sure these strings are pointer-distinct, but C-string-equal.
+  EXPECT_NE(str1, str3);
+  EXPECT_STREQ(str1, str3);
+
+  const intptr_t i1 = 1;
+  const intptr_t i2 = 2;
+
+  CStringMap<intptr_t> map;
+  EXPECT(map.IsEmpty());
+
+  map.Insert({str1, i1});
+  EXPECT_NOTNULL(map.Lookup(str1));
+  EXPECT_EQ(i1, map.LookupValue(str1));
+  EXPECT_NULLPTR(map.Lookup(str2));
+  EXPECT_NOTNULL(map.Lookup(str3));
+  EXPECT_EQ(i1, map.LookupValue(str3));
+
+  map.Insert({str2, i2});
+  EXPECT_NOTNULL(map.Lookup(str1));
+  EXPECT_EQ(i1, map.LookupValue(str1));
+  EXPECT_NOTNULL(map.Lookup(str2));
+  EXPECT_EQ(i2, map.LookupValue(str2));
+  EXPECT_NOTNULL(map.Lookup(str3));
+  EXPECT_EQ(i1, map.LookupValue(str3));
+
+  EXPECT(map.Remove(str3));
+  EXPECT_NULLPTR(map.Lookup(str1));
+  EXPECT_NOTNULL(map.Lookup(str2));
+  EXPECT_EQ(i2, map.LookupValue(str2));
+  EXPECT_NULLPTR(map.Lookup(str3));
+
+  EXPECT(!map.Remove(str3));
+  EXPECT(map.Remove(str2));
+  EXPECT(map.IsEmpty());
+
+  free(str3);
+  free(str2);
+  free(str1);
+}
+
+TEST_CASE(CStringMapUpdate) {
+  const char* const kConst1 = "test";
+  const char* const kConst2 = "test 2";
+
+  char* str1 = OS::SCreate(nullptr, "%s", kConst1);
+  char* str2 = OS::SCreate(nullptr, "%s", kConst2);
+  char* str3 = OS::SCreate(nullptr, "%s", kConst1);
+  char* str4 = OS::SCreate(nullptr, "%s", kConst1);  // Only used for lookup.
+
+  // Make sure these strings are pointer-distinct, but C-string-equal.
+  EXPECT_NE(str1, str3);
+  EXPECT_NE(str1, str4);
+  EXPECT_NE(str3, str4);
+  EXPECT_STREQ(str1, str3);
+  EXPECT_STREQ(str1, str4);
+
+  CStringKeyValueTrait<intptr_t>::Pair p1 = {str1, 1};
+  CStringKeyValueTrait<intptr_t>::Pair p2 = {str2, 2};
+  CStringKeyValueTrait<intptr_t>::Pair p3 = {str3, 3};
+
+  CStringMap<intptr_t> map;
+  EXPECT(map.IsEmpty());
+
+  map.Update(p1);
+  EXPECT_NOTNULL(map.Lookup(str1));
+  EXPECT_EQ(p1.value, map.LookupValue(str1));
+  EXPECT_NULLPTR(map.Lookup(str2));
+  EXPECT_NOTNULL(map.Lookup(str3));
+  EXPECT_EQ(p1.value, map.LookupValue(str3));
+  EXPECT_NOTNULL(map.Lookup(str4));
+  EXPECT_EQ(p1.value, map.LookupValue(str4));
+
+  map.Update(p2);
+  EXPECT_NOTNULL(map.Lookup(str1));
+  EXPECT_EQ(p1.value, map.LookupValue(str1));
+  EXPECT_NOTNULL(map.Lookup(str2));
+  EXPECT_EQ(p2.value, map.LookupValue(str2));
+  EXPECT_NOTNULL(map.Lookup(str3));
+  EXPECT_EQ(p1.value, map.LookupValue(str3));
+  EXPECT_NOTNULL(map.Lookup(str4));
+  EXPECT_EQ(p1.value, map.LookupValue(str4));
+
+  // Check Lookup after Update.
+  map.Update(p3);
+  EXPECT_NOTNULL(map.Lookup(str1));
+  EXPECT_EQ(p3.value, map.LookupValue(str1));
+  EXPECT_NOTNULL(map.Lookup(str2));
+  EXPECT_EQ(p2.value, map.LookupValue(str2));
+  EXPECT_NOTNULL(map.Lookup(str3));
+  EXPECT_EQ(p3.value, map.LookupValue(str3));
+  EXPECT_NOTNULL(map.Lookup(str4));
+  EXPECT_EQ(p3.value, map.LookupValue(str4));
+
+  // Check that single Remove after only Updates ensures Lookup fails after.
+  EXPECT(map.Remove(str3));
+  EXPECT_NULLPTR(map.Lookup(str1));
+  EXPECT_NOTNULL(map.Lookup(str2));
+  EXPECT_EQ(p2.value, map.LookupValue(str2));
+  EXPECT_NULLPTR(map.Lookup(str3));
+  EXPECT_NULLPTR(map.Lookup(str4));
+
+  EXPECT(!map.Remove(str3));
+  EXPECT(map.Remove(str2));
+  EXPECT(map.IsEmpty());
+
+  // Quick double-check that these weren't side-effected by the implementation
+  // of hash maps (p1 especially).
+  EXPECT_EQ(str1, p1.key);
+  EXPECT_EQ(1, p1.value);
+  EXPECT_EQ(str2, p2.key);
+  EXPECT_EQ(2, p2.value);
+  EXPECT_EQ(str3, p3.key);
+  EXPECT_EQ(3, p3.value);
+
+  free(str4);
+  free(str3);
+  free(str2);
+  free(str1);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/heap/become.cc b/runtime/vm/heap/become.cc
index d6feee1..ef95366 100644
--- a/runtime/vm/heap/become.cc
+++ b/runtime/vm/heap/become.cc
@@ -191,15 +191,15 @@
   OS::PrintErr("DETECTED FATAL ISSUE IN BECOME MAPPINGS\n");
 
   OS::PrintErr("BEFORE ADDRESS: %p\n", before_obj);
-  OS::PrintErr("BEFORE IS HEAP OBJECT: %s",
+  OS::PrintErr("BEFORE IS HEAP OBJECT: %s\n",
                before_obj->IsHeapObject() ? "YES" : "NO");
-  OS::PrintErr("BEFORE IN VMISOLATE HEAP OBJECT: %s",
+  OS::PrintErr("BEFORE IN VMISOLATE HEAP OBJECT: %s\n",
                before_obj->InVMIsolateHeap() ? "YES" : "NO");
 
   OS::PrintErr("AFTER ADDRESS: %p\n", after_obj);
-  OS::PrintErr("AFTER IS HEAP OBJECT: %s",
+  OS::PrintErr("AFTER IS HEAP OBJECT: %s\n",
                after_obj->IsHeapObject() ? "YES" : "NO");
-  OS::PrintErr("AFTER IN VMISOLATE HEAP OBJECT: %s",
+  OS::PrintErr("AFTER IN VMISOLATE HEAP OBJECT: %s\n",
                after_obj->InVMIsolateHeap() ? "YES" : "NO");
 
   if (before_obj->IsHeapObject()) {
diff --git a/runtime/vm/heap/freelist_test.cc b/runtime/vm/heap/freelist_test.cc
index d3a0ae9..aee898f 100644
--- a/runtime/vm/heap/freelist_test.cc
+++ b/runtime/vm/heap/freelist_test.cc
@@ -10,7 +10,7 @@
 
 static uword Allocate(FreeList* free_list, intptr_t size, bool is_protected) {
   uword result = free_list->TryAllocate(size, is_protected);
-  if (result && is_protected) {
+  if ((result != 0u) && is_protected) {
     VirtualMemory::Protect(reinterpret_cast<void*>(result), size,
                            VirtualMemory::kReadExecute);
   }
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 59a7e0b..2e9d7f4 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -432,6 +432,16 @@
   } else if (old_space_.ShouldPerformIdleMarkSweep(deadline)) {
     TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
     CollectOldSpaceGarbage(thread, kMarkSweep, kIdle);
+  } else if (old_space_.NeedsGarbageCollection()) {
+    // Even though the following GC may exceed our idle deadline, we need to
+    // ensure than that promotions during idle scavenges do not lead to
+    // unbounded growth of old space. If a program is allocating only in new
+    // space and all scavenges happen during idle time, then NotifyIdle will be
+    // the only place that checks the old space allocation limit.
+    // Compare the tail end of Heap::CollectNewSpaceGarbage.
+    CollectOldSpaceGarbage(thread, kMarkSweep, kIdle);  // Blocks for O(heap)
+  } else {
+    CheckStartConcurrentMarking(thread, kIdle);  // Blocks for up to O(roots)
   }
 }
 
@@ -575,7 +585,7 @@
   if (old_space_.AlmostNeedsGarbageCollection()) {
     if (BeginOldSpaceGC(thread)) {
       TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
-      old_space_.CollectGarbage(kMarkSweep, false /* finish */);
+      old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
       EndOldSpaceGC();
     }
   }
@@ -867,26 +877,39 @@
 
 void Heap::ForwardWeakEntries(RawObject* before_object,
                               RawObject* after_object) {
+  const auto before_space =
+      before_object->IsNewObject() ? Heap::kNew : Heap::kOld;
+  const auto after_space =
+      after_object->IsNewObject() ? Heap::kNew : Heap::kOld;
+
   for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
-    WeakTable* before_table =
-        GetWeakTable(before_object->IsNewObject() ? Heap::kNew : Heap::kOld,
-                     static_cast<Heap::WeakSelector>(sel));
+    const auto selector = static_cast<Heap::WeakSelector>(sel);
+    auto before_table = GetWeakTable(before_space, selector);
     intptr_t entry = before_table->RemoveValue(before_object);
     if (entry != 0) {
-      WeakTable* after_table =
-          GetWeakTable(after_object->IsNewObject() ? Heap::kNew : Heap::kOld,
-                       static_cast<Heap::WeakSelector>(sel));
+      auto after_table = GetWeakTable(after_space, selector);
       after_table->SetValue(after_object, entry);
     }
   }
+
+  // We only come here during hot reload, in which case we assume that none of
+  // the isolates is in the middle of sending messages.
+  RELEASE_ASSERT(isolate()->forward_table_new() == nullptr);
+  RELEASE_ASSERT(isolate()->forward_table_old() == nullptr);
 }
 
 void Heap::ForwardWeakTables(ObjectPointerVisitor* visitor) {
+  // NOTE: This method is only used by the compactor, so there is no need to
+  // process the `Heap::kNew` tables.
   for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
     WeakSelector selector = static_cast<Heap::WeakSelector>(sel);
-    GetWeakTable(Heap::kNew, selector)->Forward(visitor);
     GetWeakTable(Heap::kOld, selector)->Forward(visitor);
   }
+
+  // Isolates might have forwarding tables (used for during snapshoting in
+  // isolate communication).
+  auto table_old = isolate()->forward_table_old();
+  if (table_old != nullptr) table_old->Forward(visitor);
 }
 
 #ifndef PRODUCT
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 7ec1f0c..4a85864 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -355,8 +355,8 @@
     page->set_next(large_pages_);
     large_pages_ = page;
 
-    // Only one object in this page (at least until String::MakeExternal or
-    // Array::MakeFixedLength is called).
+    // Only one object in this page (at least until Array::MakeFixedLength
+    // is called).
     page->set_object_end(page->object_start() + size);
   }
   return page;
@@ -410,6 +410,9 @@
 }
 
 void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) {
+  // Thread should be at a safepoint when this code is called and hence
+  // it is not necessary to lock large_pages_.
+  ASSERT(Thread::Current()->IsAtSafepoint());
   IncreaseCapacityInWords(-(page->memory_->size() >> kWordSizeLog2));
   // Remove the page from the list.
   if (previous_page != NULL) {
@@ -775,6 +778,7 @@
 }
 
 void PageSpace::VisitRememberedCards(ObjectPointerVisitor* visitor) const {
+  ASSERT(Thread::Current()->IsAtSafepoint());
   for (HeapPage* page = large_pages_; page != NULL; page = page->next()) {
     page->VisitRememberedCards(visitor);
   }
@@ -1498,11 +1502,7 @@
   idle_gc_threshold_in_words_ =
       after.CombinedCapacityInWords() + 2 * kPageSizeInWords;
 
-  if (FLAG_log_growth) {
-    THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=gc\n",
-              heap_->isolate()->name(), gc_threshold_in_words_ / KBInWords,
-              idle_gc_threshold_in_words_ / KBInWords);
-  }
+  RecordUpdate(before, after, "gc");
 }
 
 void PageSpaceController::EvaluateAfterLoading(SpaceUsage after) {
@@ -1526,11 +1526,30 @@
   idle_gc_threshold_in_words_ =
       after.CombinedCapacityInWords() + 2 * kPageSizeInWords;
 
+  RecordUpdate(after, after, "loaded");
+}
+
+void PageSpaceController::RecordUpdate(SpaceUsage before,
+                                       SpaceUsage after,
+                                       const char* reason) {
+#if defined(SUPPORT_TIMELINE)
+  TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "UpdateGrowthLimit");
+  tds.SetNumArguments(5);
+  tds.CopyArgument(0, "Reason", reason);
+  tds.FormatArgument(1, "Before.CombinedCapacity (kB)", "%" Pd "",
+                     RoundWordsToKB(before.CombinedCapacityInWords()));
+  tds.FormatArgument(2, "After.CombinedCapacity (kB)", "%" Pd "",
+                     RoundWordsToKB(after.CombinedCapacityInWords()));
+  tds.FormatArgument(3, "Threshold (kB)", "%" Pd "",
+                     RoundWordsToKB(gc_threshold_in_words_));
+  tds.FormatArgument(4, "Idle Threshold (kB)", "%" Pd "",
+                     RoundWordsToKB(idle_gc_threshold_in_words_));
+#endif
+
   if (FLAG_log_growth) {
-    THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd
-              "kB, reason=loaded\n",
+    THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=%s\n",
               heap_->isolate()->name(), gc_threshold_in_words_ / KBInWords,
-              idle_gc_threshold_in_words_ / KBInWords);
+              idle_gc_threshold_in_words_ / KBInWords, reason);
   }
 }
 
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 6eb1e32..736fa30 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -232,6 +232,8 @@
   bool is_enabled() { return is_enabled_; }
 
  private:
+  void RecordUpdate(SpaceUsage before, SpaceUsage after, const char* reason);
+
   Heap* heap_;
 
   bool is_enabled_;
@@ -257,9 +259,6 @@
   // Perform a synchronous GC when capacity exceeds this amount.
   intptr_t gc_threshold_in_words_;
 
-  // Perform a synchronous GC when external allocations exceed this amount.
-  intptr_t gc_external_threshold_in_words_;
-
   // Start considering idle GC when capacity exceeds this amount.
   intptr_t idle_gc_threshold_in_words_;
 
diff --git a/runtime/vm/heap/safepoint.cc b/runtime/vm/heap/safepoint.cc
index 0c25411..3bf198b 100644
--- a/runtime/vm/heap/safepoint.cc
+++ b/runtime/vm/heap/safepoint.cc
@@ -45,16 +45,17 @@
   Isolate* I = T->isolate();
   ASSERT(I != NULL);
 
-  Heap* heap = I->heap();
-  current_growth_controller_state_ = heap->GrowthControlState();
-  heap->DisableGrowthControl();
-
   SafepointHandler* handler = I->group()->safepoint_handler();
   ASSERT(handler != NULL);
 
   // Signal all threads to get to a safepoint and wait for them to
   // get to a safepoint.
   handler->SafepointThreads(T);
+
+  // N.B.: Change growth policy inside the safepoint to prevent racy access.
+  Heap* heap = I->heap();
+  current_growth_controller_state_ = heap->GrowthControlState();
+  heap->DisableGrowthControl();
 }
 
 ForceGrowthSafepointOperationScope::~ForceGrowthSafepointOperationScope() {
@@ -63,14 +64,15 @@
   Isolate* I = T->isolate();
   ASSERT(I != NULL);
 
+  // N.B.: Change growth policy inside the safepoint to prevent racy access.
+  Heap* heap = I->heap();
+  heap->SetGrowthControlState(current_growth_controller_state_);
+
   // Resume all threads which are blocked for the safepoint operation.
   SafepointHandler* handler = I->safepoint_handler();
   ASSERT(handler != NULL);
   handler->ResumeThreads(T);
 
-  Heap* heap = I->heap();
-  heap->SetGrowthControlState(current_growth_controller_state_);
-
   if (current_growth_controller_state_) {
     ASSERT(T->CanCollectGarbage());
     // Check if we passed the growth limit during the scope.
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 966b581..accb638 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -847,12 +847,8 @@
 }
 
 void Scavenger::ProcessWeakReferences() {
-  // Rehash the weak tables now that we know which objects survive this cycle.
-  for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
-    WeakTable* table =
-        heap_->GetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel));
-    heap_->SetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel),
-                        WeakTable::NewFrom(table));
+  auto rehash_weak_table = [](WeakTable* table, WeakTable* replacement_new,
+                              WeakTable* replacement_old) {
     intptr_t size = table->size();
     for (intptr_t i = 0; i < size; i++) {
       if (table->IsValidEntryAt(i)) {
@@ -864,16 +860,40 @@
           // The object has survived.  Preserve its record.
           uword new_addr = ForwardedAddr(header);
           raw_obj = RawObject::FromAddr(new_addr);
-          heap_->SetWeakEntry(raw_obj, static_cast<Heap::WeakSelector>(sel),
-                              table->ValueAt(i));
+          auto replacement =
+              raw_obj->IsNewObject() ? replacement_new : replacement_old;
+          replacement->SetValue(raw_obj, table->ValueAt(i));
         }
       }
     }
+  };
+
+  // Rehash the weak tables now that we know which objects survive this cycle.
+  for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
+    const auto selector = static_cast<Heap::WeakSelector>(sel);
+    auto table = heap_->GetWeakTable(Heap::kNew, selector);
+    auto table_old = heap_->GetWeakTable(Heap::kOld, selector);
+
+    // Create a new weak table for the new-space.
+    auto table_new = WeakTable::NewFrom(table);
+    rehash_weak_table(table, table_new, table_old);
+    heap_->SetWeakTable(Heap::kNew, selector, table_new);
+
     // Remove the old table as it has been replaced with the newly allocated
     // table above.
     delete table;
   }
 
+  // Each isolate might have a weak table used for fast snapshot writing (i.e.
+  // isolate communication). Rehash those tables if need be.
+  auto isolate = heap_->isolate();
+  auto table = isolate->forward_table_new();
+  if (table != NULL) {
+    auto replacement = WeakTable::NewFrom(table);
+    rehash_weak_table(table, replacement, isolate->forward_table_old());
+    isolate->set_forward_table_new(replacement);
+  }
+
   // The queued weak properties at this point do not refer to reachable keys,
   // so we clear their key and value fields.
   {
diff --git a/runtime/vm/heap/spaces.h b/runtime/vm/heap/spaces.h
index 2885ef5..e2737e4 100644
--- a/runtime/vm/heap/spaces.h
+++ b/runtime/vm/heap/spaces.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_HEAP_SPACES_H_
 #define RUNTIME_VM_HEAP_SPACES_H_
 
+#include "platform/globals.h"
+
 // This file contains utilities shared by old and new space.
 // TODO(koda): Create Space base class with Space::CurrentUsage().
 
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index 81d4f0b..cfe0874 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -89,8 +89,8 @@
     words_to_end = (raw_obj->HeapSize() >> kWordSizeLog2);
   }
 #ifdef DEBUG
-  // String::MakeExternal and Array::MakeFixedLength create trailing filler
-  // objects, but they are always unreachable. Verify that they are not marked.
+  // Array::MakeFixedLength creates trailing filler objects,
+  // but they are always unreachable. Verify that they are not marked.
   uword current = RawObject::ToAddr(raw_obj) + raw_obj->HeapSize();
   uword end = page->object_end();
   while (current < end) {
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 84c0316..03672dc 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -556,6 +556,11 @@
 void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
   Zone* zone = Thread::Current()->zone();
 
+#if defined(DART_PRECOMPILER)
+  const char* bss_symbol =
+      vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
+#endif
+
   const char* instructions_symbol =
       vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
   assembly_stream_.Print(".text\n");
@@ -570,8 +575,16 @@
   // look like a HeapPage.
   intptr_t instructions_length = next_text_offset_;
   WriteWordLiteralText(instructions_length);
+
+#if defined(DART_PRECOMPILER)
+  assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
+                         instructions_symbol);
+#else
+  WriteWordLiteralText(0);  // No relocations.
+#endif
+
   intptr_t header_words = Image::kHeaderSize / sizeof(compiler::target::uword);
-  for (intptr_t i = 1; i < header_words; i++) {
+  for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
     WriteWordLiteralText(0);
   }
 
@@ -579,6 +592,7 @@
 
   Object& owner = Object::Handle(zone);
   String& str = String::Handle(zone);
+  PcDescriptors& descriptors = PcDescriptors::Handle(zone);
 
   ObjectStore* object_store = Isolate::Current()->object_store();
 
@@ -613,6 +627,7 @@
 
     const Instructions& insns = *data.insns_;
     const Code& code = *data.code_;
+    descriptors = data.code_->pc_descriptors();
 
     if (profile_writer_ != nullptr) {
       const intptr_t offset = Image::kHeaderSize + text_offset;
@@ -717,7 +732,27 @@
       ASSERT(Utils::IsAligned(entry, sizeof(uword)));
       ASSERT(Utils::IsAligned(end, sizeof(uword)));
 
+#if defined(DART_PRECOMPILER)
+      PcDescriptors::Iterator iterator(descriptors,
+                                       RawPcDescriptors::kBSSRelocation);
+      uword next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
+
+      for (uword cursor = entry; cursor < end;
+           cursor += sizeof(compiler::target::uword*)) {
+        compiler::target::uword data =
+            *reinterpret_cast<compiler::target::uword*>(cursor);
+        if ((cursor - entry) == next_reloc_offset) {
+          assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
+                                 bss_symbol, /*addend=*/data);
+          next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
+        } else {
+          WriteWordLiteralText(data);
+        }
+      }
+      text_offset += end - entry;
+#else
       text_offset += WriteByteSequence(entry, end);
+#endif
     }
 
     ASSERT((text_offset - instr_start) == insns.raw()->HeapSize());
@@ -725,6 +760,16 @@
 
   FrameUnwindEpilogue();
 
+#if defined(DART_PRECOMPILER)
+  assembly_stream_.Print(".bss\n");
+  assembly_stream_.Print("%s:\n", bss_symbol);
+
+  // Currently we only put one symbol in the data section, the address of
+  // DLRT_GetThreadForNativeCallback, which is populated when the snapshot is
+  // loaded.
+  WriteWordLiteralText(0);
+#endif
+
 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) ||                  \
     defined(TARGET_OS_FUCHSIA)
   assembly_stream_.Print(".section .rodata\n");
@@ -860,24 +905,42 @@
 }
 
 void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+  const intptr_t instructions_length = next_text_offset_;
 #ifdef DART_PRECOMPILER
   intptr_t segment_base = 0;
   if (elf_ != nullptr) {
     segment_base = elf_->NextMemoryOffset();
   }
+
+  // Calculate the start of the BSS section based on the known size of the
+  // text section and page alignment.
+  intptr_t bss_base = 0;
+  if (elf_ != nullptr) {
+    bss_base =
+        Utils::RoundUp(segment_base + instructions_length, Elf::kPageSize);
+  }
 #endif
 
   // This header provides the gap to make the instructions snapshot look like a
   // HeapPage.
-  intptr_t instructions_length = next_text_offset_;
   instructions_blob_stream_.WriteWord(instructions_length);
+#if defined(DART_PRECOMPILER)
+  instructions_blob_stream_.WriteWord(elf_ != nullptr ? bss_base - segment_base
+                                                      : 0);
+#else
+  instructions_blob_stream_.WriteWord(0);  // No relocations.
+#endif
   intptr_t header_words = Image::kHeaderSize / sizeof(uword);
-  for (intptr_t i = 1; i < header_words; i++) {
+  for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
     instructions_blob_stream_.WriteWord(0);
   }
 
   intptr_t text_offset = 0;
 
+#if defined(DART_PRECOMPILER)
+  PcDescriptors& descriptors = PcDescriptors::Handle();
+#endif
+
   NoSafepointScope no_safepoint;
   for (intptr_t i = 0; i < instructions_.length(); i++) {
     auto& data = instructions_[i];
@@ -928,6 +991,8 @@
     marked_tags |= static_cast<uword>(insns.raw_ptr()->hash_) << 32;
 #endif
 
+    intptr_t payload_stream_start = 0;
+
 #if defined(IS_SIMARM_X64)
     const intptr_t start_offset = instructions_blob_stream_.bytes_written();
     const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.Size());
@@ -938,6 +1003,7 @@
     instructions_blob_stream_.WriteFixed<uint32_t>(
         insns.raw_ptr()->unchecked_entrypoint_pc_offset_);
     instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment);
+    payload_stream_start = instructions_blob_stream_.Position();
     instructions_blob_stream_.WriteBytes(
         reinterpret_cast<const void*>(insns.PayloadStart()), insns.Size());
     instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment);
@@ -945,16 +1011,61 @@
     text_offset += (end_offset - start_offset);
     USE(end);
 #else   // defined(IS_SIMARM_X64)
+    payload_stream_start = instructions_blob_stream_.Position() +
+                           (insns.PayloadStart() - beginning);
+
     instructions_blob_stream_.WriteWord(marked_tags);
     text_offset += sizeof(uword);
     beginning += sizeof(uword);
     text_offset += WriteByteSequence(beginning, end);
 #endif  // defined(IS_SIMARM_X64)
 
+#if defined(DART_PRECOMPILER)
+    // Don't patch the relocation if we're not generating ELF. The regular blobs
+    // format does not yet support these relocations. Use
+    // Code::VerifyBSSRelocations to check whether the relocations are patched
+    // or not after loading.
+    if (elf_ != nullptr) {
+      const intptr_t current_stream_position =
+          instructions_blob_stream_.Position();
+
+      descriptors = data.code_->pc_descriptors();
+
+      PcDescriptors::Iterator iterator(
+          descriptors, /*kind_mask=*/RawPcDescriptors::kBSSRelocation);
+
+      while (iterator.MoveNext()) {
+        const intptr_t reloc_offset = iterator.PcOffset();
+
+        // The instruction stream at the relocation position holds an offset
+        // into BSS corresponding to the symbol being resolved. This addend is
+        // factored into the relocation.
+        const auto addend = *reinterpret_cast<compiler::target::word*>(
+            insns.PayloadStart() + reloc_offset);
+
+        // Overwrite the relocation position in the instruction stream with the
+        // (positive) offset of the start of the payload from the start of the
+        // BSS segment plus the addend in the relocation.
+        instructions_blob_stream_.SetPosition(payload_stream_start +
+                                              reloc_offset);
+
+        const uword offset =
+            bss_base - (segment_base + payload_stream_start + reloc_offset) +
+            addend;
+        instructions_blob_stream_.WriteTargetWord(offset);
+      }
+
+      // Restore stream position after the relocation was patched.
+      instructions_blob_stream_.SetPosition(current_stream_position);
+    }
+#endif
+
     ASSERT((text_offset - instr_start) ==
            ImageWriter::SizeInSnapshot(insns.raw()));
   }
 
+  ASSERT(instructions_blob_stream_.bytes_written() == instructions_length);
+
 #ifdef DART_PRECOMPILER
   if (elf_ != nullptr) {
     const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions"
@@ -963,6 +1074,9 @@
         elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
                       instructions_blob_stream_.bytes_written());
     ASSERT(segment_base == segment_base2);
+
+    const intptr_t real_bss_base = elf_->AddBSSData("_kDartVMBSSData", 8);
+    ASSERT(bss_base == real_bss_base);
   }
 #endif
 }
@@ -976,7 +1090,6 @@
       shared_data_image_(shared_data_image),
       shared_instructions_image_(shared_instructions_image) {
   ASSERT(data_image != NULL);
-  ASSERT(instructions_image != NULL);
 }
 
 RawApiError* ImageReader::VerifyAlignment() const {
@@ -993,6 +1106,7 @@
 }
 
 RawInstructions* ImageReader::GetInstructionsAt(int32_t offset) const {
+  ASSERT(instructions_image_ != nullptr);
   ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
 
   RawObject* result;
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 5acb75d..deb94ef 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -48,6 +48,11 @@
     return snapshot_size - kHeaderSize;
   }
 
+  uword bss_offset() const {
+    return *(reinterpret_cast<const uword*>(raw_memory_) + 1);
+  }
+
+  static constexpr intptr_t kHeaderFields = 2;
   static const intptr_t kHeaderSize = OS::kMaxPreferredCodeAlignment;
 
  private:
@@ -314,8 +319,15 @@
   void FrameUnwindPrologue();
   void FrameUnwindEpilogue();
   intptr_t WriteByteSequence(uword start, uword end);
+
+#if defined(TARGET_ARCH_IS_64_BIT)
+  const char* kLiteralPrefix = ".quad";
+#else
+  const char* kLiteralPrefix = ".long";
+#endif
+
   void WriteWordLiteralText(compiler::target::uword value) {
-// Padding is helpful for comparing the .S with --disassemble.
+    // Padding is helpful for comparing the .S with --disassemble.
 #if defined(TARGET_ARCH_IS_64_BIT)
     assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
 #else
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index fa8075c..77bd91d 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -13,6 +13,7 @@
 
 #include "vm/compiler/assembler/assembler.h"
 #include "vm/compiler/assembler/disassembler_kbc.h"
+#include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/frontend/bytecode_reader.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/cpu.h"
@@ -389,6 +390,9 @@
     }
   }
 #endif
+  // Make sure interpreter's unboxing view is consistent with compiler.
+  supports_unboxed_doubles_ = FlowGraphCompiler::SupportsUnboxedDoubles();
+  supports_unboxed_simd128_ = FlowGraphCompiler::SupportsUnboxedSimd128();
 }
 
 Interpreter::~Interpreter() {
@@ -1780,7 +1784,6 @@
 
   {
     BYTECODE(Throw, A);
-    DEBUG_CHECK;
     {
       SP[1] = 0;  // Space for result.
       Exit(thread, FP, SP + 2, pc);
@@ -2264,7 +2267,6 @@
 
   {
     BYTECODE(StoreStaticTOS, D);
-    DEBUG_CHECK;
     RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
     RawInstance* value = static_cast<RawInstance*>(*SP--);
     field->StorePointer(&field->ptr()->value_.static_value_, value, thread);
@@ -2318,7 +2320,7 @@
         (field->ptr()->is_nullable_ != kNullCid) &&
         Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
     classid_t guarded_cid = field->ptr()->guarded_cid_;
-    if (unboxing && (guarded_cid == kDoubleCid)) {
+    if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
       double raw_value = Double::RawCast(value)->ptr()->value_;
       ASSERT(*(reinterpret_cast<RawDouble**>(instance->ptr()) +
                offset_in_words) == null_value);  // Initializing store.
@@ -2330,7 +2332,8 @@
       instance->StorePointer(
           reinterpret_cast<RawDouble**>(instance->ptr()) + offset_in_words, box,
           thread);
-    } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
       ASSERT(*(reinterpret_cast<RawFloat32x4**>(instance->ptr()) +
@@ -2343,7 +2346,8 @@
       instance->StorePointer(
           reinterpret_cast<RawFloat32x4**>(instance->ptr()) + offset_in_words,
           box, thread);
-    } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
       ASSERT(*(reinterpret_cast<RawFloat64x2**>(instance->ptr()) +
@@ -2590,7 +2594,7 @@
   {
     BYTECODE(AssertBoolean, A);
     RawObject* value = SP[0];
-    if (rA) {  // Should we perform type check?
+    if (rA != 0u) {  // Should we perform type check?
       if ((value == true_value) || (value == false_value)) {
         goto AssertBooleanOk;
       }
@@ -3079,20 +3083,23 @@
         (field->ptr()->is_nullable_ != kNullCid) &&
         Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
     classid_t guarded_cid = field->ptr()->guarded_cid_;
-    if (unboxing && (guarded_cid == kDoubleCid)) {
+    if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
+      ASSERT(FlowGraphCompiler::SupportsUnboxedDoubles());
       double raw_value = Double::RawCast(value)->ptr()->value_;
       // AllocateDouble places result at SP[0]
       if (!AllocateDouble(thread, raw_value, pc, FP, SP)) {
         HANDLE_EXCEPTION;
       }
-    } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
       // AllocateFloat32x4 places result at SP[0]
       if (!AllocateFloat32x4(thread, raw_value, pc, FP, SP)) {
         HANDLE_EXCEPTION;
       }
-    } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
       // AllocateFloat64x2 places result at SP[0]
@@ -3194,20 +3201,22 @@
         (field->ptr()->is_nullable_ != kNullCid) &&
         Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
     classid_t guarded_cid = field->ptr()->guarded_cid_;
-    if (unboxing && (guarded_cid == kDoubleCid)) {
+    if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
       double raw_value = Double::RawCast(value)->ptr()->value_;
       RawDouble* box =
           *(reinterpret_cast<RawDouble**>(instance->ptr()) + offset_in_words);
       ASSERT(box != null_value);  // Non-initializing store.
       box->ptr()->value_ = raw_value;
-    } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
       RawFloat32x4* box = *(reinterpret_cast<RawFloat32x4**>(instance->ptr()) +
                             offset_in_words);
       ASSERT(box != null_value);  // Non-initializing store.
       raw_value.writeTo(box->ptr()->value_);
-    } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+    } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+               supports_unboxed_simd128_) {
       simd128_value_t raw_value;
       raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
       RawFloat64x2* box = *(reinterpret_cast<RawFloat64x2**>(instance->ptr()) +
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index fd40ec5..4889a5a 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -275,7 +275,11 @@
   bool is_debugging_;
 #endif  // !PRODUCT
 
+  bool supports_unboxed_doubles_;
+  bool supports_unboxed_simd128_;
+
   friend class InterpreterSetjmpBuffer;
+
   DISALLOW_COPY_AND_ASSIGN(Interpreter);
 };
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index a31c59b..c341416 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -79,11 +79,6 @@
     FLAG_concurrent_mark = false;         // Timing dependent.
     FLAG_concurrent_sweep = false;        // Timing dependent.
     FLAG_random_seed = 0x44617274;        // "Dart"
-#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-    FLAG_load_deferred_eagerly = true;
-#else
-    COMPILE_ASSERT(FLAG_load_deferred_eagerly);
-#endif
   }
 }
 
@@ -676,7 +671,7 @@
     I->ScheduleInterrupts(Thread::kMessageInterrupt);
   }
   Dart_MessageNotifyCallback callback = I->message_notify_callback();
-  if (callback) {
+  if (callback != nullptr) {
     // Allow the embedder to handle message notification.
     (*callback)(Api::CastIsolate(I));
   }
@@ -2009,6 +2004,15 @@
 }
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 
+void Isolate::set_forward_table_new(WeakTable* table) {
+  std::unique_ptr<WeakTable> value(table);
+  forward_table_new_ = std::move(value);
+}
+void Isolate::set_forward_table_old(WeakTable* table) {
+  std::unique_ptr<WeakTable> value(table);
+  forward_table_old_ = std::move(value);
+}
+
 void Isolate::Shutdown() {
   ASSERT(this == Isolate::Current());
   BackgroundCompiler::Stop(this);
@@ -2810,7 +2814,7 @@
   // SafepointMonitorLocker to ensure the lock has safepoint checks.
   SafepointMonitorLocker ml(isolates_list_monitor_);
   Isolate* current = isolates_list_head_;
-  while (current) {
+  while (current != nullptr) {
     visitor->VisitIsolate(current);
     current = current->next_;
   }
@@ -2878,7 +2882,7 @@
   }
   Isolate* previous = nullptr;
   Isolate* current = isolates_list_head_;
-  while (current) {
+  while (current != nullptr) {
     if (current == isolate) {
       ASSERT(previous != nullptr);
       previous->next_ = current->next_;
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e8df2bb..48895f3 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -90,6 +90,7 @@
 class StubCode;
 class ThreadRegistry;
 class UserTag;
+class WeakTable;
 
 class PendingLazyDeopt {
  public:
@@ -779,18 +780,6 @@
     isolate_flags_ = RemappingCidsBit::update(value, isolate_flags_);
   }
 
-  static const intptr_t kInvalidGen = 0;
-
-  void IncrLoadingInvalidationGen() {
-    AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
-    if (loading_invalidation_gen_ == kInvalidGen) {
-      AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
-    }
-  }
-  intptr_t loading_invalidation_gen() {
-    return AtomicOperations::LoadRelaxed(&loading_invalidation_gen_);
-  }
-
   // Used by background compiler which field became boxed and must trigger
   // deoptimization in the mutator thread.
   void AddDeoptimizingBoxedField(const Field& field);
@@ -957,6 +946,14 @@
 
   void MaybeIncreaseReloadEveryNStackOverflowChecks();
 
+  // The weak table used in the snapshot writer for the purpose of fast message
+  // sending.
+  WeakTable* forward_table_new() { return forward_table_new_.get(); }
+  void set_forward_table_new(WeakTable* table);
+
+  WeakTable* forward_table_old() { return forward_table_old_.get(); }
+  void set_forward_table_old(WeakTable* table);
+
   static void NotifyLowMemory();
 
  private:
@@ -1170,11 +1167,6 @@
   // Isolate list next pointer.
   Isolate* next_ = nullptr;
 
-  // Invalidation generations; used to track events occurring in parallel
-  // to background compilation. The counters may overflow, which is OK
-  // since we check for equality to detect if an event occured.
-  intptr_t loading_invalidation_gen_ = kInvalidGen;
-
   // Protect access to boxed_field_list_.
   Mutex field_list_mutex_;
   // List of fields that became boxed and that trigger deoptimization.
@@ -1193,6 +1185,10 @@
 
   ReversePcLookupCache* reverse_pc_lookup_cache_ = nullptr;
 
+  // Used during message sending of messages between isolates.
+  std::unique_ptr<WeakTable> forward_table_new_;
+  std::unique_ptr<WeakTable> forward_table_old_;
+
   static Dart_IsolateGroupCreateCallback create_group_callback_;
   static Dart_InitializeIsolateCallback initialize_callback_;
   static Dart_IsolateShutdownCallback shutdown_callback_;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index c4bbc70..640c358 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -83,7 +83,7 @@
 }
 
 void InstanceMorpher::ComputeMapping() {
-  if (from_.NumTypeArguments()) {
+  if (from_.NumTypeArguments() > 0) {
     // Add copying of the optional type argument field.
     intptr_t from_offset = from_.type_arguments_field_offset();
     ASSERT(from_offset != Class::kNoTypeArguments);
@@ -217,7 +217,7 @@
 
 void InstanceMorpher::DumpFormatFor(const Class& cls) const {
   THR_Print("%s\n", cls.ToCString());
-  if (cls.NumTypeArguments()) {
+  if (cls.NumTypeArguments() > 0) {
     intptr_t field_offset = cls.type_arguments_field_offset();
     ASSERT(field_offset != Class::kNoTypeArguments);
     THR_Print("  - @%" Pd " <type arguments>\n", field_offset);
@@ -377,18 +377,14 @@
     if (obj.IsLibrary()) {
       return Library::Cast(obj).UrlHash();
     } else if (obj.IsClass()) {
-      if (Class::Cast(obj).id() == kFreeListElement) {
-        return 0;
-      }
       return String::HashRawSymbol(Class::Cast(obj).Name());
     } else if (obj.IsField()) {
       return String::HashRawSymbol(Field::Cast(obj).name());
-    } else if (obj.IsInstance()) {
-      Object& hashObj = Object::Handle(Instance::Cast(obj).HashCode());
-      if (hashObj.IsError()) {
-        Exceptions::PropagateError(Error::Cast(hashObj));
-      }
-      return Smi::Cast(hashObj).Value();
+    } else if (obj.IsClosure()) {
+      return String::HashRawSymbol(
+          Function::Handle(Closure::Cast(obj).function()).name());
+    } else {
+      FATAL1("Unexpected type in become: %s\n", obj.ToCString());
     }
     return 0;
   }
@@ -730,7 +726,7 @@
   // Ensure all functions on the stack have unoptimized code.
   EnsuredUnoptimizedCodeForStack();
   // Deoptimize all code that had optimizing decisions that are dependent on
-  // assumptions from field guards or CHA or deferred library prefixes.
+  // assumptions from field guards or CHA.
   // TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
   // is paranoid. This likely can be moved to the commit phase.
   DeoptimizeDependentCode();
@@ -958,8 +954,6 @@
   }
 
   DeoptimizeTypeTestingStubs();
-
-  // TODO(johnmccutchan): Also call LibraryPrefix::InvalidateDependentCode.
 }
 
 void IsolateReloadContext::CheckpointClasses() {
@@ -976,9 +970,8 @@
   // Copy the size of the class table.
   saved_num_cids_ = I->class_table()->NumCids();
 
-  // Copy of the class table.
-  ClassAndSize* local_saved_class_table = reinterpret_cast<ClassAndSize*>(
-      malloc(sizeof(ClassAndSize) * saved_num_cids_));
+  ClassAndSize* saved_class_table = nullptr;
+  class_table->CopyBeforeHotReload(&saved_class_table, &saved_num_cids_);
 
   // Copy classes into saved_class_table_ first. Make sure there are no
   // safepoints until saved_class_table_ is filled up and saved so class raw
@@ -986,18 +979,12 @@
   {
     NoSafepointScope no_safepoint_scope(Thread::Current());
 
-    for (intptr_t i = 0; i < saved_num_cids_; i++) {
-      if (class_table->IsValidIndex(i) && class_table->HasValidClassAt(i)) {
-        // Copy the class into the saved class table.
-        local_saved_class_table[i] = class_table->PairAt(i);
-      } else {
-        // No class at this index, mark it as NULL.
-        local_saved_class_table[i] = ClassAndSize(NULL);
-      }
-    }
+    // The saved_class_table_ is now source of truth for GC.
+    AtomicOperations::StoreRelease(&saved_class_table_, saved_class_table);
 
-    // Elements of saved_class_table_ are now visible to GC.
-    saved_class_table_ = local_saved_class_table;
+    // We can therefore wipe out all of the old entries (if that table is used
+    // for GC during the hot-reload we have a bug).
+    class_table->ResetBeforeHotReload();
   }
 
   // Add classes to the set. Set is stored in the Array, so adding an element
@@ -1030,20 +1017,6 @@
   return (*file_modified_callback_)(url_chars, since);
 }
 
-static void PropagateLibraryModified(
-    const ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>* imported_by,
-    intptr_t lib_index,
-    BitVector* modified_libs) {
-  ZoneGrowableArray<intptr_t>* dep_libs = (*imported_by)[lib_index];
-  for (intptr_t i = 0; i < dep_libs->length(); i++) {
-    intptr_t dep_lib_index = (*dep_libs)[i];
-    if (!modified_libs->Contains(dep_lib_index)) {
-      modified_libs->Add(dep_lib_index);
-      PropagateLibraryModified(imported_by, dep_lib_index, modified_libs);
-    }
-  }
-}
-
 static bool ContainsScriptUri(const GrowableArray<const char*>& seen_uris,
                               const char* uri) {
   for (intptr_t i = 0; i < seen_uris.length(); i++) {
@@ -1116,109 +1089,6 @@
   }
 }
 
-BitVector* IsolateReloadContext::FindModifiedLibraries(bool force_reload,
-                                                       bool root_lib_modified) {
-  Thread* thread = Thread::Current();
-  int64_t last_reload = I->last_reload_timestamp();
-
-  const GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(object_store()->libraries());
-  Library& lib = Library::Handle();
-  Array& scripts = Array::Handle();
-  Script& script = Script::Handle();
-  intptr_t num_libs = libs.Length();
-
-  // Construct the imported-by graph.
-  ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>* imported_by = new (zone_)
-      ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>(zone_, num_libs);
-  imported_by->SetLength(num_libs);
-  for (intptr_t i = 0; i < num_libs; i++) {
-    (*imported_by)[i] = new (zone_) ZoneGrowableArray<intptr_t>(zone_, 0);
-  }
-  Array& ports = Array::Handle();
-  Namespace& ns = Namespace::Handle();
-  Library& target = Library::Handle();
-
-  for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) {
-    lib ^= libs.At(lib_idx);
-    ASSERT(lib_idx == lib.index());
-    if (lib.is_dart_scheme()) {
-      // We don't care about imports among dart scheme libraries.
-      continue;
-    }
-
-    // Add imports to the import-by graph.
-    ports = lib.imports();
-    for (intptr_t import_idx = 0; import_idx < ports.Length(); import_idx++) {
-      ns ^= ports.At(import_idx);
-      if (!ns.IsNull()) {
-        target = ns.library();
-        (*imported_by)[target.index()]->Add(lib.index());
-      }
-    }
-
-    // Add exports to the import-by graph.
-    ports = lib.exports();
-    for (intptr_t export_idx = 0; export_idx < ports.Length(); export_idx++) {
-      ns ^= ports.At(export_idx);
-      if (!ns.IsNull()) {
-        target = ns.library();
-        (*imported_by)[target.index()]->Add(lib.index());
-      }
-    }
-
-    // Add prefixed imports to the import-by graph.
-    DictionaryIterator entries(lib);
-    Object& entry = Object::Handle();
-    LibraryPrefix& prefix = LibraryPrefix::Handle();
-    while (entries.HasNext()) {
-      entry = entries.GetNext();
-      if (entry.IsLibraryPrefix()) {
-        prefix ^= entry.raw();
-        ports = prefix.imports();
-        for (intptr_t import_idx = 0; import_idx < ports.Length();
-             import_idx++) {
-          ns ^= ports.At(import_idx);
-          if (!ns.IsNull()) {
-            target = ns.library();
-            (*imported_by)[target.index()]->Add(lib.index());
-          }
-        }
-      }
-    }
-  }
-
-  BitVector* modified_libs = new (Z) BitVector(Z, num_libs);
-
-  if (root_lib_modified) {
-    // The root library was either moved or replaced. Mark it as modified to
-    // force a reload of the potential root library replacement.
-    lib = object_store()->root_library();
-    modified_libs->Add(lib.index());
-  }
-
-  for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) {
-    lib ^= libs.At(lib_idx);
-    if (lib.is_dart_scheme() || modified_libs->Contains(lib_idx)) {
-      // We don't consider dart scheme libraries during reload.  If
-      // the modified libs set already contains this library, then we
-      // have already visited it.
-      continue;
-    }
-    scripts = lib.LoadedScripts();
-    for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) {
-      script ^= scripts.At(script_idx);
-      if (force_reload || ScriptModifiedSince(script, last_reload)) {
-        modified_libs->Add(lib_idx);
-        PropagateLibraryModified(imported_by, lib_idx, modified_libs);
-        break;
-      }
-    }
-  }
-
-  return modified_libs;
-}
-
 void IsolateReloadContext::CheckpointLibraries() {
   TIMELINE_SCOPE(CheckpointLibraries);
   TIR_Print("---- CHECKPOINTING LIBRARIES\n");
@@ -1276,16 +1146,8 @@
   TIR_Print("---- ROLLING BACK CLASS TABLE\n");
   ASSERT(saved_num_cids_ > 0);
   ASSERT(saved_class_table_ != NULL);
-  ClassTable* class_table = I->class_table();
-  class_table->SetNumCids(saved_num_cids_);
-  // Overwrite classes in class table with the saved classes.
-  for (intptr_t i = 0; i < saved_num_cids_; i++) {
-    if (class_table->IsValidIndex(i)) {
-      class_table->SetAt(i, saved_class_table_[i].get_raw_class());
-    }
-  }
 
-  DiscardSavedClassTable();
+  DiscardSavedClassTable(/*is_rollback=*/true);
 }
 
 void IsolateReloadContext::RollbackLibraries() {
@@ -1381,8 +1243,7 @@
     return;
   }
 
-  ASSERT(new_cls.is_finalized() == old_cls.is_finalized());
-  if (!new_cls.is_finalized()) {
+  if (!old_cls.is_finalized()) {
     if (new_cls.SourceFingerprint() == old_cls.SourceFingerprint()) {
       return;
     }
@@ -1391,6 +1252,7 @@
     changed_in_last_reload.Add(new_cls);
     return;
   }
+  ASSERT(new_cls.is_finalized());
 
   Zone* zone = Thread::Current()->zone();
   const Array& functions = Array::Handle(zone, new_cls.functions());
@@ -1680,7 +1542,7 @@
   TIMELINE_SCOPE(MorphInstances);
   if (!HasInstanceMorphers()) {
     // Fast path: no class had a shape change.
-    DiscardSavedClassTable();
+    DiscardSavedClassTable(/*is_rollback=*/false);
     return;
   }
 
@@ -1702,7 +1564,7 @@
   intptr_t count = locator.count();
   if (count == 0) {
     // Fast path: classes with shape change have no instances.
-    DiscardSavedClassTable();
+    DiscardSavedClassTable(/*is_rollback=*/false);
     return;
   }
 
@@ -1746,8 +1608,10 @@
     saved_class_table_[i] = ClassAndSize(nullptr, -1);
   }
 #endif
-  free(saved_class_table_);
-  saved_class_table_ = nullptr;
+
+  // We accepted the hot-reload and morphed instances. So now we can commit to
+  // the changed class table and deleted the saved one.
+  DiscardSavedClassTable(/*is_rollback=*/false);
 
   Become::ElementsForwardIdentity(before, after);
   // The heap now contains only instances with the new size. Ordinary GC is safe
@@ -1812,7 +1676,7 @@
 
 RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
   ClassAndSize* class_table =
-      AtomicOperations::LoadRelaxed(&saved_class_table_);
+      AtomicOperations::LoadAcquire(&saved_class_table_);
   if (class_table != NULL) {
     ASSERT(cid > 0);
     ASSERT(cid < saved_num_cids_);
@@ -1824,7 +1688,7 @@
 
 intptr_t IsolateReloadContext::GetClassSizeForHeapWalkAt(intptr_t cid) {
   ClassAndSize* class_table =
-      AtomicOperations::LoadRelaxed(&saved_class_table_);
+      AtomicOperations::LoadAcquire(&saved_class_table_);
   if (class_table != NULL) {
     ASSERT(cid > 0);
     ASSERT(cid < saved_num_cids_);
@@ -1834,14 +1698,12 @@
   }
 }
 
-void IsolateReloadContext::DiscardSavedClassTable() {
+void IsolateReloadContext::DiscardSavedClassTable(bool is_rollback) {
   ClassAndSize* local_saved_class_table = saved_class_table_;
-  saved_class_table_ = nullptr;
-  // Can't free this table immediately as another thread (e.g., concurrent
-  // marker or sweeper) may be between loading the table pointer and loading the
-  // table element. The table will be freed at the next major GC or isolate
-  // shutdown.
-  I->class_table()->AddOldTable(local_saved_class_table);
+  I->class_table()->ResetAfterHotReload(local_saved_class_table,
+                                        saved_num_cids_, is_rollback);
+  AtomicOperations::StoreRelease(&saved_class_table_,
+                                 static_cast<ClassAndSize*>(nullptr));
 }
 
 RawLibrary* IsolateReloadContext::saved_root_library() const {
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 3f8fa18..300195e 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -173,7 +173,7 @@
   // Prefers old classes when we are in the middle of a reload.
   RawClass* GetClassForHeapWalkAt(intptr_t cid);
   intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
-  void DiscardSavedClassTable();
+  void DiscardSavedClassTable(bool is_rollback);
 
   void RegisterClass(const Class& new_cls);
 
@@ -236,7 +236,6 @@
   void CheckpointClasses();
 
   bool ScriptModifiedSince(const Script& script, int64_t since);
-  BitVector* FindModifiedLibraries(bool force_reload, bool root_lib_modified);
   void FindModifiedSources(Thread* thread,
                            bool force_reload,
                            Dart_SourceFile** modified_sources,
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 02e02bf..42d125f 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -2151,6 +2151,7 @@
       "  final int zero = 0;\n"
       "}\n"
       "main() {\n"
+      "  return new Fruit().zero.toString();\n"
       "}\n";
 
   Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
@@ -2163,12 +2164,12 @@
       "  final int zero = 0;\n"
       "}\n"
       "main() {\n"
-      "  return 'yes';\n"
+      "  return new Fruit().zero.toString();\n"
       "}\n";
 
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
   EXPECT_VALID(lib);
-  EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+  EXPECT_STREQ("0", SimpleInvokeStr(lib, "main"));
 
   const char* kReloadScript =
       "enum Fruit {\n"
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 30cddd2..33a990c 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -270,7 +270,7 @@
 
 const char* JSONStream::LookupParam(const char* key) const {
   for (int i = 0; i < num_params(); i++) {
-    if (!strcmp(key, param_keys_[i])) {
+    if (strcmp(key, param_keys_[i]) == 0) {
       return param_values_[i];
     }
   }
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index bad2258..009cab2 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,13 +20,14 @@
 
 // Both version numbers are inclusive.
 static const uint32_t kMinSupportedKernelFormatVersion = 18;
-static const uint32_t kMaxSupportedKernelFormatVersion = 29;
+static const uint32_t kMaxSupportedKernelFormatVersion = 31;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
   V(Nothing, 0)                                                                \
   V(Something, 1)                                                              \
   V(Class, 2)                                                                  \
+  V(Extension, 115)                                                            \
   V(FunctionNode, 3)                                                           \
   V(Field, 4)                                                                  \
   V(Constructor, 5)                                                            \
@@ -66,6 +67,7 @@
   V(SetConcatenation, 112)                                                     \
   V(MapConcatenation, 113)                                                     \
   V(InstanceCreation, 114)                                                     \
+  V(FileUriExpression, 116)                                                    \
   V(IsExpression, 37)                                                          \
   V(AsExpression, 38)                                                          \
   V(StringLiteral, 39)                                                         \
@@ -123,9 +125,6 @@
   V(TypeParameterType, 95)                                                     \
   V(SimpleInterfaceType, 96)                                                   \
   V(SimpleFunctionType, 97)                                                    \
-  V(NullReference, 99)                                                         \
-  V(ClassReference, 100)                                                       \
-  V(MemberReference, 101)                                                      \
   V(ConstantExpression, 106)                                                   \
   V(Deprecated_ConstantExpression, 107)                                        \
   V(SpecializedVariableGet, 128)                                               \
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 44c558a..b591aef 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1139,23 +1139,33 @@
 
   ActiveClassScope active_class_scope(&active_class_, &toplevel_class);
 
-  if (FLAG_enable_interpreter || FLAG_use_bytecode_compiler) {
-    static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                  "Cleanup support for old bytecode format versions");
-    ASSERT(!toplevel_class.is_declared_in_bytecode());
-    if (bytecode_metadata_helper_.ReadMembers(library_kernel_offset_,
-                                              toplevel_class, false)) {
-      ASSERT(toplevel_class.is_loaded());
-      return;
-    }
-  }
-
   // Offsets within library index are whole program offsets and not
   // relative to the library.
   const intptr_t correction = correction_offset_ - library_kernel_offset_;
   helper_.SetOffset(library_index.ClassOffset(library_index.class_count()) +
                     correction);
 
+  if (kernel_binary_version_ >= 30) {
+    const intptr_t extension_count = helper_.ReadListLength();
+    for (intptr_t i = 0; i < extension_count; ++i) {
+      helper_.ReadTag();                     // read tag.
+      helper_.SkipCanonicalNameReference();  // skip canonical name.
+      helper_.SkipStringReference();         // skip name.
+      helper_.ReadUInt();                    // read source uri index.
+      helper_.ReadPosition();                // read file offset.
+      helper_.SkipTypeParametersList();      // skip type parameter list.
+      helper_.SkipDartType();                // skip on-type.
+
+      const intptr_t extension_member_count = helper_.ReadListLength();
+      for (intptr_t j = 0; j < extension_member_count; ++j) {
+        helper_.SkipName();                    // skip name.
+        helper_.ReadByte();                    // read kind.
+        helper_.ReadByte();                    // read flags.
+        helper_.SkipCanonicalNameReference();  // skip member reference
+      }
+    }
+  }
+
   fields_.Clear();
   functions_.Clear();
 
@@ -1295,7 +1305,7 @@
       for (intptr_t n = 0; n < name_count; ++n) {
         String& show_hide_name =
             H.DartSymbolObfuscate(helper_.ReadStringReference());
-        if (flags & LibraryDependencyHelper::Show) {
+        if ((flags & LibraryDependencyHelper::Show) != 0) {
           show_list.Add(show_hide_name, Heap::kOld);
         } else {
           hide_list.Add(show_hide_name, Heap::kOld);
@@ -1330,7 +1340,7 @@
     }
     String& prefix = H.DartSymbolPlain(dependency_helper.name_index_);
     ns = Namespace::New(target_library, show_names, hide_names);
-    if (dependency_helper.flags_ & LibraryDependencyHelper::Export) {
+    if ((dependency_helper.flags_ & LibraryDependencyHelper::Export) != 0) {
       library->AddExport(ns);
     } else {
       if (prefix.IsNull() || prefix.Length() == 0) {
@@ -1342,7 +1352,8 @@
         } else {
           library_prefix = LibraryPrefix::New(
               prefix, ns,
-              dependency_helper.flags_ & LibraryDependencyHelper::Deferred,
+              (dependency_helper.flags_ & LibraryDependencyHelper::Deferred) !=
+                  0,
               *library);
           library->AddObject(library_prefix, prefix);
         }
@@ -1499,18 +1510,6 @@
   // fields.
   const bool discard_fields = klass.InjectCIDFields();
 
-  if (FLAG_enable_interpreter || FLAG_use_bytecode_compiler) {
-    static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
-                  "Cleanup support for old bytecode format versions");
-    ASSERT(!klass.is_declared_in_bytecode());
-    if (bytecode_metadata_helper_.ReadMembers(
-            klass.kernel_offset() + library_kernel_offset_, klass,
-            discard_fields)) {
-      ASSERT(klass.is_loaded());
-      return;
-    }
-  }
-
   fields_.Clear();
   functions_.Clear();
   if (!discard_fields) {
diff --git a/runtime/vm/malloc_hooks_test.cc b/runtime/vm/malloc_hooks_test.cc
index 28c6009..80dc9d1 100644
--- a/runtime/vm/malloc_hooks_test.cc
+++ b/runtime/vm/malloc_hooks_test.cc
@@ -180,7 +180,7 @@
 
   char* var = static_cast<char*>(malloc(16 * sizeof(char)));
   JSONStream js;
-  ProfilerService::PrintNativeAllocationJSON(&js, Profile::kNoTags, -1, -1);
+  ProfilerService::PrintNativeAllocationJSON(&js, -1, -1, false);
   const char* json = js.ToCString();
 
   // Check that all the stack frames from the current down to main are actually
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 3edc7b2..19deb0a 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -13,10 +13,9 @@
 
 namespace dart {
 
-RawMegamorphicCache* MegamorphicCacheTable::LookupOriginal(
-    Thread* thread,
-    const String& name,
-    const Array& descriptor) {
+RawMegamorphicCache* MegamorphicCacheTable::Lookup(Thread* thread,
+                                                   const String& name,
+                                                   const Array& descriptor) {
   Isolate* isolate = thread->isolate();
   // Multiple compilation threads could access this lookup.
   SafepointMutexLocker ml(isolate->megamorphic_mutex());
@@ -45,31 +44,6 @@
   return cache.raw();
 }
 
-RawMegamorphicCache* MegamorphicCacheTable::LookupClone(
-    Thread* thread,
-    const String& name,
-    const Array& descriptor) {
-  if (!Compiler::IsBackgroundCompilation()) {
-    return LookupOriginal(thread, name, descriptor);
-  }
-
-  auto& cloned_caches = thread->compiler_state().cloned_megamorphic_caches();
-  for (intptr_t i = 0; i < cloned_caches.length(); i++) {
-    const MegamorphicCache& cache = *cloned_caches[i];
-    if ((cache.target_name() == name.raw()) &&
-        (cache.arguments_descriptor() == descriptor.raw())) {
-      return cache.raw();
-    }
-  }
-
-  const auto& original =
-      MegamorphicCache::Handle(LookupOriginal(thread, name, descriptor));
-  const auto& clone =
-      MegamorphicCache::ZoneHandle(MegamorphicCache::Clone(original));
-  cloned_caches.Add(&clone);
-  return clone.raw();
-}
-
 RawFunction* MegamorphicCacheTable::miss_handler(Isolate* isolate) {
   ASSERT(isolate->object_store()->megamorphic_miss_function() !=
          Function::null());
diff --git a/runtime/vm/megamorphic_cache_table.h b/runtime/vm/megamorphic_cache_table.h
index c3c40d5..6b68c6c 100644
--- a/runtime/vm/megamorphic_cache_table.h
+++ b/runtime/vm/megamorphic_cache_table.h
@@ -39,16 +39,9 @@
       static void ReInitMissHandlerCode(Isolate* isolate,
                                         compiler::ObjectPoolBuilder* wrapper));
 
-  // Lookup a cache for querying type feedback. The result may not be mutated by
-  // another thread.
-  static RawMegamorphicCache* LookupClone(Thread* thread,
-                                          const String& name,
-                                          const Array& descriptor);
-  // Lookup a cache for insertion into compiled code. The result may be mutated
-  // by the another thread.
-  static RawMegamorphicCache* LookupOriginal(Thread* thread,
-                                             const String& name,
-                                             const Array& descriptor);
+  static RawMegamorphicCache* Lookup(Thread* thread,
+                                     const String& name,
+                                     const Array& descriptor);
 
   static void PrintSizes(Isolate* isolate);
 };
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index 0951509..d945b97 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -130,7 +130,7 @@
     MonitorLocker ml(&monitor_);
     if (FLAG_trace_isolates) {
       Isolate* source_isolate = Isolate::Current();
-      if (source_isolate) {
+      if (source_isolate != nullptr) {
         OS::PrintErr(
             "[>] Posting message:\n"
             "\tlen:        %" Pd "\n\tsource:     (%" Pd64
@@ -416,7 +416,7 @@
 #endif  // !defined(PRODUCT)
 
     if (status == kOK) {
-      if (start_callback_) {
+      if (start_callback_ != nullptr) {
         // Initialize the message handler by running its start function,
         // if we have one.  For an isolate, this will run the isolate's
         // main() function.
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 2739b43..f1306b1 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -139,14 +139,18 @@
   auto port =
       ::Dart_NewNativePort("service-rpc", &Utils::HandleResponse, false);
   if (port == ILLEGAL_PORT) {
-    return Api::NewError("Was unable to create native port.");
+    if (error != nullptr) {
+      *error = strdup("Was unable to create native port.");
+    }
+    return false;
   }
 
   // Before sending the message we'll lock the monitor, which the receiver
   // will later on notify once the answer has been received.
   MonitorLocker monitor(vm_service_call_monitor);
 
-  if (ServiceIsolate::SendServiceRpc(request_json, request_json_length, port)) {
+  if (ServiceIsolate::SendServiceRpc(request_json, request_json_length, port,
+                                     error)) {
     // We posted successfully and expect the vm-service to send the reply, so
     // we will wait for it now.
     auto wait_result = monitor.Wait();
@@ -170,14 +174,6 @@
     // We couldn't post the message and will not receive any reply. Therefore we
     // clean up the port and return an error.
     Dart_CloseNativePort(port);
-
-    if (error != nullptr) {
-      if (ServiceIsolate::Port() == ILLEGAL_PORT) {
-        *error = strdup("No service isolate port was found.");
-      } else {
-        *error = strdup("Was unable to post message to service isolate.");
-      }
-    }
     return false;
   }
 }
@@ -251,20 +247,20 @@
 DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg) {
   if (!FLAG_enable_testing_pragmas) return nullptr;
 
-  if (!strcmp(command, "gc-on-nth-allocation")) {
+  if (strcmp(command, "gc-on-nth-allocation") == 0) {
     TransitionNativeToVM _(Thread::Current());
     intptr_t argument = reinterpret_cast<intptr_t>(arg);
     ASSERT(argument > 0);
     Isolate::Current()->heap()->CollectOnNthAllocation(argument);
     return nullptr;
 
-  } else if (!strcmp(command, "gc-now")) {
+  } else if (strcmp(command, "gc-now") == 0) {
     ASSERT(arg == nullptr);  // Don't pass an argument to this command.
     TransitionNativeToVM _(Thread::Current());
     Isolate::Current()->heap()->CollectAllGarbage();
     return nullptr;
 
-  } else if (!strcmp(command, "is-mutator-in-native")) {
+  } else if (strcmp(command, "is-mutator-in-native") == 0) {
     Isolate* const isolate = reinterpret_cast<Isolate*>(arg);
     if (isolate->mutator_thread()->execution_state() ==
         Thread::kThreadInNative) {
@@ -273,7 +269,7 @@
       return nullptr;
     }
 
-  } else if (!strcmp(command, "run-in-safepoint-and-rw-code")) {
+  } else if (strcmp(command, "run-in-safepoint-and-rw-code") == 0) {
     const RunInSafepointAndRWCodeArgs* const args =
         reinterpret_cast<RunInSafepointAndRWCodeArgs*>(arg);
     Thread::EnterIsolateAsHelper(args->isolate, Thread::TaskKind::kUnknownTask);
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index ab948de..8d07143 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -120,7 +120,8 @@
     if ((function_bits & (kClosureFunctionBit | kInstanceFunctionBit)) ==
         (kClosureFunctionBit | kInstanceFunctionBit)) {
       // Retrieve the receiver from the context.
-      const int closure_index = (function_bits & kGenericFunctionBit) ? 1 : 0;
+      const int closure_index =
+          (function_bits & kGenericFunctionBit) != 0 ? 1 : 0;
       const Object& closure = Object::Handle(ArgAt(closure_index));
       const Context& context =
           Context::Handle(Closure::Cast(closure).context());
@@ -268,17 +269,17 @@
 
   // Returns true if the arguments are those of an instance function call.
   bool ToInstanceFunction() const {
-    return (FunctionBits::decode(argc_tag_) & kInstanceFunctionBit);
+    return (FunctionBits::decode(argc_tag_) & kInstanceFunctionBit) != 0;
   }
 
   // Returns true if the arguments are those of a closure function call.
   bool ToClosureFunction() const {
-    return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit);
+    return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit) != 0;
   }
 
   // Returns true if the arguments are those of a generic function call.
   bool ToGenericFunction() const {
-    return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit);
+    return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit) != 0;
   }
 
   int NumHiddenArgs(int function_bits) const {
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index a4a5ee5..6878c45 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -35,15 +35,6 @@
 
 #define NATIVE_ENTRY_FUNCTION(name) BootstrapNatives::DN_##name
 
-#ifdef DEBUG
-#define SET_NATIVE_RETVAL(args, value)                                         \
-  RawObject* retval = value;                                                   \
-  ASSERT(retval->IsDartInstance());                                            \
-  arguments->SetReturnUnsafe(retval);
-#else
-#define SET_NATIVE_RETVAL(arguments, value) arguments->SetReturnUnsafe(value);
-#endif
-
 #define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count)         \
   static RawObject* DN_Helper##name(Isolate* isolate, Thread* thread,          \
                                     Zone* zone, NativeArguments* arguments);   \
@@ -63,9 +54,15 @@
       Isolate* isolate = thread->isolate();                                    \
       TransitionGeneratedToVM transition(thread);                              \
       StackZone zone(thread);                                                  \
-      SET_NATIVE_RETVAL(                                                       \
-          arguments,                                                           \
-          DN_Helper##name(isolate, thread, zone.GetZone(), arguments));        \
+      /* Be careful holding return_value_unsafe without a handle here. */      \
+      /* A return of Object::sentinel means the return value has already */    \
+      /* been set. */                                                          \
+      RawObject* return_value_unsafe =                                         \
+          DN_Helper##name(isolate, thread, zone.GetZone(), arguments);         \
+      if (return_value_unsafe != Object::sentinel().raw()) {                   \
+        ASSERT(return_value_unsafe->IsDartInstance());                         \
+        arguments->SetReturnUnsafe(return_value_unsafe);                       \
+      }                                                                        \
       DEOPTIMIZE_ALOT;                                                         \
     }                                                                          \
     VERIFY_ON_TRANSITION;                                                      \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 93e43d5..5dbc67b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -90,6 +90,7 @@
 DECLARE_FLAG(bool, trace_reload);
 DECLARE_FLAG(bool, write_protect_code);
 DECLARE_FLAG(bool, precompiled_mode);
+DECLARE_FLAG(int, max_polymorphic_checks);
 
 static const char* const kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
@@ -552,19 +553,19 @@
   }
 
   // Allocate and initialize the null class.
-  cls = Class::New<Instance>(kNullCid);
+  cls = Class::New<Instance>(kNullCid, isolate);
   cls.set_num_type_arguments(0);
   isolate->object_store()->set_null_class(cls);
 
   // Allocate and initialize the free list element class.
-  cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement);
+  cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement, isolate);
   cls.set_num_type_arguments(0);
   cls.set_is_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
 
   // Allocate and initialize the forwarding corpse class.
-  cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse);
+  cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse, isolate);
   cls.set_num_type_arguments(0);
   cls.set_is_finalized();
   cls.set_is_declaration_loaded();
@@ -588,138 +589,138 @@
   }
 
   // Allocate the remaining VM internal classes.
-  cls = Class::New<TypeArguments>();
+  cls = Class::New<TypeArguments>(isolate);
   type_arguments_class_ = cls.raw();
 
-  cls = Class::New<PatchClass>();
+  cls = Class::New<PatchClass>(isolate);
   patch_class_class_ = cls.raw();
 
-  cls = Class::New<Function>();
+  cls = Class::New<Function>(isolate);
   function_class_ = cls.raw();
 
-  cls = Class::New<ClosureData>();
+  cls = Class::New<ClosureData>(isolate);
   closure_data_class_ = cls.raw();
 
-  cls = Class::New<SignatureData>();
+  cls = Class::New<SignatureData>(isolate);
   signature_data_class_ = cls.raw();
 
-  cls = Class::New<RedirectionData>();
+  cls = Class::New<RedirectionData>(isolate);
   redirection_data_class_ = cls.raw();
 
-  cls = Class::New<FfiTrampolineData>();
+  cls = Class::New<FfiTrampolineData>(isolate);
   ffi_trampoline_data_class_ = cls.raw();
 
-  cls = Class::New<Field>();
+  cls = Class::New<Field>(isolate);
   field_class_ = cls.raw();
 
-  cls = Class::New<Script>();
+  cls = Class::New<Script>(isolate);
   script_class_ = cls.raw();
 
-  cls = Class::New<Library>();
+  cls = Class::New<Library>(isolate);
   library_class_ = cls.raw();
 
-  cls = Class::New<Namespace>();
+  cls = Class::New<Namespace>(isolate);
   namespace_class_ = cls.raw();
 
-  cls = Class::New<KernelProgramInfo>();
+  cls = Class::New<KernelProgramInfo>(isolate);
   kernel_program_info_class_ = cls.raw();
 
-  cls = Class::New<Code>();
+  cls = Class::New<Code>(isolate);
   code_class_ = cls.raw();
 
-  cls = Class::New<Bytecode>();
+  cls = Class::New<Bytecode>(isolate);
   bytecode_class_ = cls.raw();
 
-  cls = Class::New<Instructions>();
+  cls = Class::New<Instructions>(isolate);
   instructions_class_ = cls.raw();
 
-  cls = Class::New<ObjectPool>();
+  cls = Class::New<ObjectPool>(isolate);
   object_pool_class_ = cls.raw();
 
-  cls = Class::New<PcDescriptors>();
+  cls = Class::New<PcDescriptors>(isolate);
   pc_descriptors_class_ = cls.raw();
 
-  cls = Class::New<CodeSourceMap>();
+  cls = Class::New<CodeSourceMap>(isolate);
   code_source_map_class_ = cls.raw();
 
-  cls = Class::New<StackMap>();
+  cls = Class::New<StackMap>(isolate);
   stackmap_class_ = cls.raw();
 
-  cls = Class::New<LocalVarDescriptors>();
+  cls = Class::New<LocalVarDescriptors>(isolate);
   var_descriptors_class_ = cls.raw();
 
-  cls = Class::New<ExceptionHandlers>();
+  cls = Class::New<ExceptionHandlers>(isolate);
   exception_handlers_class_ = cls.raw();
 
-  cls = Class::New<Context>();
+  cls = Class::New<Context>(isolate);
   context_class_ = cls.raw();
 
-  cls = Class::New<ContextScope>();
+  cls = Class::New<ContextScope>(isolate);
   context_scope_class_ = cls.raw();
 
-  cls = Class::New<ParameterTypeCheck>();
+  cls = Class::New<ParameterTypeCheck>(isolate);
   dyncalltypecheck_class_ = cls.raw();
 
-  cls = Class::New<SingleTargetCache>();
+  cls = Class::New<SingleTargetCache>(isolate);
   singletargetcache_class_ = cls.raw();
 
-  cls = Class::New<UnlinkedCall>();
+  cls = Class::New<UnlinkedCall>(isolate);
   unlinkedcall_class_ = cls.raw();
 
-  cls = Class::New<ICData>();
+  cls = Class::New<ICData>(isolate);
   icdata_class_ = cls.raw();
 
-  cls = Class::New<MegamorphicCache>();
+  cls = Class::New<MegamorphicCache>(isolate);
   megamorphic_cache_class_ = cls.raw();
 
-  cls = Class::New<SubtypeTestCache>();
+  cls = Class::New<SubtypeTestCache>(isolate);
   subtypetestcache_class_ = cls.raw();
 
-  cls = Class::New<ApiError>();
+  cls = Class::New<ApiError>(isolate);
   api_error_class_ = cls.raw();
 
-  cls = Class::New<LanguageError>();
+  cls = Class::New<LanguageError>(isolate);
   language_error_class_ = cls.raw();
 
-  cls = Class::New<UnhandledException>();
+  cls = Class::New<UnhandledException>(isolate);
   unhandled_exception_class_ = cls.raw();
 
-  cls = Class::New<UnwindError>();
+  cls = Class::New<UnwindError>(isolate);
   unwind_error_class_ = cls.raw();
 
   ASSERT(class_class() != null_);
 
   // Pre-allocate classes in the vm isolate so that we can for example create a
   // symbol table and populate it with some frequently used strings as symbols.
-  cls = Class::New<Array>();
+  cls = Class::New<Array>(isolate);
   isolate->object_store()->set_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset());
   cls.set_num_type_arguments(1);
-  cls = Class::New<Array>(kImmutableArrayCid);
+  cls = Class::New<Array>(kImmutableArrayCid, isolate);
   isolate->object_store()->set_immutable_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset());
   cls.set_num_type_arguments(1);
-  cls = Class::New<GrowableObjectArray>();
+  cls = Class::New<GrowableObjectArray>(isolate);
   isolate->object_store()->set_growable_object_array_class(cls);
   cls.set_type_arguments_field_offset(
       GrowableObjectArray::type_arguments_offset());
   cls.set_num_type_arguments(1);
-  cls = Class::NewStringClass(kOneByteStringCid);
+  cls = Class::NewStringClass(kOneByteStringCid, isolate);
   isolate->object_store()->set_one_byte_string_class(cls);
-  cls = Class::NewStringClass(kTwoByteStringCid);
+  cls = Class::NewStringClass(kTwoByteStringCid, isolate);
   isolate->object_store()->set_two_byte_string_class(cls);
-  cls = Class::New<Mint>();
+  cls = Class::New<Mint>(isolate);
   isolate->object_store()->set_mint_class(cls);
-  cls = Class::New<Double>();
+  cls = Class::New<Double>(isolate);
   isolate->object_store()->set_double_class(cls);
 
   // Ensure that class kExternalTypedDataUint8ArrayCid is registered as we
   // need it when reading in the token stream of bootstrap classes in the VM
   // isolate.
-  Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid);
+  Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid, isolate);
 
   // Needed for object pools of VM isolate stubs.
-  Class::NewTypedDataClass(kTypedDataInt8ArrayCid);
+  Class::NewTypedDataClass(kTypedDataInt8ArrayCid, isolate);
 
   // Allocate and initialize the empty_array instance.
   {
@@ -832,7 +833,7 @@
   // as we do not have any VM isolate snapshot at this time.
   *vm_isolate_snapshot_object_table_ = Object::empty_array().raw();
 
-  cls = Class::New<Instance>(kDynamicCid);
+  cls = Class::New<Instance>(kDynamicCid, isolate);
   cls.set_is_abstract();
   cls.set_num_type_arguments(0);
   cls.set_is_finalized();
@@ -840,14 +841,14 @@
   cls.set_is_type_finalized();
   dynamic_class_ = cls.raw();
 
-  cls = Class::New<Instance>(kVoidCid);
+  cls = Class::New<Instance>(kVoidCid, isolate);
   cls.set_num_type_arguments(0);
   cls.set_is_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
   void_class_ = cls.raw();
 
-  cls = Class::New<Type>();
+  cls = Class::New<Type>(isolate);
   cls.set_is_finalized();
   cls.set_is_declaration_loaded();
   cls.set_is_type_finalized();
@@ -868,7 +869,7 @@
   cls.SetFunctions(Object::empty_array());
 
   // Allocate and initialize singleton true and false boolean objects.
-  cls = Class::New<Bool>();
+  cls = Class::New<Bool>(isolate);
   isolate->object_store()->set_bool_class(cls);
   *bool_true_ = Bool::New(true);
   *bool_false_ = Bool::New(false);
@@ -1398,7 +1399,7 @@
 
     // All RawArray fields will be initialized to an empty array, therefore
     // initialize array class first.
-    cls = Class::New<Array>();
+    cls = Class::New<Array>(isolate);
     object_store->set_array_class(cls);
 
     // VM classes that are parameterized (Array, ImmutableArray,
@@ -1411,7 +1412,7 @@
 
     // Set up the growable object array class (Has to be done after the array
     // class is setup as one of its field is an array object).
-    cls = Class::New<GrowableObjectArray>();
+    cls = Class::New<GrowableObjectArray>(isolate);
     object_store->set_growable_object_array_class(cls);
     cls.set_type_arguments_field_offset(
         GrowableObjectArray::type_arguments_offset());
@@ -1430,19 +1431,20 @@
     object_store->set_canonical_type_arguments(array);
 
     // Setup type class early in the process.
-    const Class& type_cls = Class::Handle(zone, Class::New<Type>());
-    const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
+    const Class& type_cls = Class::Handle(zone, Class::New<Type>(isolate));
+    const Class& type_ref_cls =
+        Class::Handle(zone, Class::New<TypeRef>(isolate));
     const Class& type_parameter_cls =
-        Class::Handle(zone, Class::New<TypeParameter>());
+        Class::Handle(zone, Class::New<TypeParameter>(isolate));
     const Class& library_prefix_cls =
-        Class::Handle(zone, Class::New<LibraryPrefix>());
+        Class::Handle(zone, Class::New<LibraryPrefix>(isolate));
 
     // Pre-allocate the OneByteString class needed by the symbol table.
-    cls = Class::NewStringClass(kOneByteStringCid);
+    cls = Class::NewStringClass(kOneByteStringCid, isolate);
     object_store->set_one_byte_string_class(cls);
 
     // Pre-allocate the TwoByteString class needed by the symbol table.
-    cls = Class::NewStringClass(kTwoByteStringCid);
+    cls = Class::NewStringClass(kTwoByteStringCid, isolate);
     object_store->set_two_byte_string_class(cls);
 
     // Setup the symbol table for the symbols created in the isolate.
@@ -1486,7 +1488,7 @@
     RegisterPrivateClass(cls, Symbols::_GrowableList(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<Array>(kImmutableArrayCid);
+    cls = Class::New<Array>(kImmutableArrayCid, isolate);
     object_store->set_immutable_array_class(cls);
     cls.set_type_arguments_field_offset(Array::type_arguments_offset());
     cls.set_num_type_arguments(1);
@@ -1504,12 +1506,12 @@
     RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::NewStringClass(kExternalOneByteStringCid);
+    cls = Class::NewStringClass(kExternalOneByteStringCid, isolate);
     object_store->set_external_one_byte_string_class(cls);
     RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::NewStringClass(kExternalTwoByteStringCid);
+    cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate);
     object_store->set_external_two_byte_string_class(cls);
     RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib);
     pending_classes.Add(cls);
@@ -1527,29 +1529,30 @@
     ASSERT(!isolate_lib.IsNull());
     ASSERT(isolate_lib.raw() == Library::IsolateLibrary());
 
-    cls = Class::New<Capability>();
+    cls = Class::New<Capability>(isolate);
     RegisterPrivateClass(cls, Symbols::_CapabilityImpl(), isolate_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<ReceivePort>();
+    cls = Class::New<ReceivePort>(isolate);
     RegisterPrivateClass(cls, Symbols::_RawReceivePortImpl(), isolate_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<SendPort>();
+    cls = Class::New<SendPort>(isolate);
     RegisterPrivateClass(cls, Symbols::_SendPortImpl(), isolate_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<TransferableTypedData>();
+    cls = Class::New<TransferableTypedData>(isolate);
     RegisterPrivateClass(cls, Symbols::_TransferableTypedDataImpl(),
                          isolate_lib);
     pending_classes.Add(cls);
 
-    const Class& stacktrace_cls = Class::Handle(zone, Class::New<StackTrace>());
+    const Class& stacktrace_cls =
+        Class::Handle(zone, Class::New<StackTrace>(isolate));
     RegisterPrivateClass(stacktrace_cls, Symbols::_StackTrace(), core_lib);
     pending_classes.Add(stacktrace_cls);
     // Super type set below, after Object is allocated.
 
-    cls = Class::New<RegExp>();
+    cls = Class::New<RegExp>(isolate);
     RegisterPrivateClass(cls, Symbols::_RegExp(), core_lib);
     pending_classes.Add(cls);
 
@@ -1559,7 +1562,7 @@
     // The script and token index of these pre-allocated classes is set up in
     // the parser when the corelib script is compiled (see
     // Parser::ParseClassDefinition).
-    cls = Class::New<Instance>(kInstanceCid);
+    cls = Class::New<Instance>(kInstanceCid, isolate);
     object_store->set_object_class(cls);
     cls.set_name(Symbols::Object());
     cls.set_num_type_arguments(0);
@@ -1569,12 +1572,12 @@
     type = Type::NewNonParameterizedType(cls);
     object_store->set_object_type(type);
 
-    cls = Class::New<Bool>();
+    cls = Class::New<Bool>(isolate);
     object_store->set_bool_class(cls);
     RegisterClass(cls, Symbols::Bool(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<Instance>(kNullCid);
+    cls = Class::New<Instance>(kNullCid, isolate);
     object_store->set_null_class(cls);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
@@ -1596,33 +1599,33 @@
                          core_lib);
     pending_classes.Add(type_parameter_cls);
 
-    cls = Class::New<Integer>();
+    cls = Class::New<Integer>(isolate);
     object_store->set_integer_implementation_class(cls);
     RegisterPrivateClass(cls, Symbols::_IntegerImplementation(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<Smi>();
+    cls = Class::New<Smi>(isolate);
     object_store->set_smi_class(cls);
     RegisterPrivateClass(cls, Symbols::_Smi(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<Mint>();
+    cls = Class::New<Mint>(isolate);
     object_store->set_mint_class(cls);
     RegisterPrivateClass(cls, Symbols::_Mint(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<Double>();
+    cls = Class::New<Double>(isolate);
     object_store->set_double_class(cls);
     RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
     pending_classes.Add(cls);
 
     // Class that represents the Dart class _Closure and C++ class Closure.
-    cls = Class::New<Closure>();
+    cls = Class::New<Closure>(isolate);
     object_store->set_closure_class(cls);
     RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
     pending_classes.Add(cls);
 
-    cls = Class::New<WeakProperty>();
+    cls = Class::New<WeakProperty>(isolate);
     object_store->set_weak_property_class(cls);
     RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
 
@@ -1639,7 +1642,7 @@
     ASSERT(!lib.IsNull());
     ASSERT(lib.raw() == Library::MirrorsLibrary());
 
-    cls = Class::New<MirrorReference>();
+    cls = Class::New<MirrorReference>(isolate);
     RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
 #endif
 
@@ -1655,7 +1658,7 @@
     object_store->set_bootstrap_library(ObjectStore::kCollection, lib);
     ASSERT(!lib.IsNull());
     ASSERT(lib.raw() == Library::CollectionLibrary());
-    cls = Class::New<LinkedHashMap>();
+    cls = Class::New<LinkedHashMap>(isolate);
     object_store->set_linked_hash_map_class(cls);
     cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset());
     cls.set_num_type_arguments(2);
@@ -1673,7 +1676,7 @@
     object_store->set_bootstrap_library(ObjectStore::kDeveloper, lib);
     ASSERT(!lib.IsNull());
     ASSERT(lib.raw() == Library::DeveloperLibrary());
-    cls = Class::New<UserTag>();
+    cls = Class::New<UserTag>(isolate);
     RegisterPrivateClass(cls, Symbols::_UserTag(), lib);
     pending_classes.Add(cls);
 
@@ -1694,66 +1697,69 @@
     ASSERT(!lib.IsNull());
     ASSERT(lib.raw() == Library::TypedDataLibrary());
 #define REGISTER_TYPED_DATA_CLASS(clazz)                                       \
-  cls = Class::NewTypedDataClass(kTypedData##clazz##ArrayCid);                 \
+  cls = Class::NewTypedDataClass(kTypedData##clazz##ArrayCid, isolate);        \
   RegisterPrivateClass(cls, Symbols::_##clazz##List(), lib);
 
     DART_CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
 #undef REGISTER_TYPED_DATA_CLASS
 #define REGISTER_TYPED_DATA_VIEW_CLASS(clazz)                                  \
-  cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid);              \
+  cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid, isolate);     \
   RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib);                   \
   pending_classes.Add(cls);
 
     CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
 
-    cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+    cls = Class::NewTypedDataViewClass(kByteDataViewCid, isolate);
     RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
     pending_classes.Add(cls);
 
 #undef REGISTER_TYPED_DATA_VIEW_CLASS
 #define REGISTER_EXT_TYPED_DATA_CLASS(clazz)                                   \
-  cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);      \
+  cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid,       \
+                                         isolate);                             \
   RegisterPrivateClass(cls, Symbols::_External##clazz(), lib);
 
-    cls = Class::New<Instance>(kByteBufferCid);
+    cls =
+        Class::New<Instance>(kByteBufferCid, isolate, /*register_class=*/false);
     cls.set_instance_size(0);
     cls.set_next_field_offset(-kWordSize);
+    isolate->RegisterClass(cls);
     RegisterPrivateClass(cls, Symbols::_ByteBuffer(), lib);
     pending_classes.Add(cls);
 
     CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
 #undef REGISTER_EXT_TYPED_DATA_CLASS
     // Register Float32x4, Int32x4, and Float64x2 in the object store.
-    cls = Class::New<Float32x4>();
+    cls = Class::New<Float32x4>(isolate);
     RegisterPrivateClass(cls, Symbols::_Float32x4(), lib);
     pending_classes.Add(cls);
     object_store->set_float32x4_class(cls);
 
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, Symbols::Float32x4(), lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
     type = Type::NewNonParameterizedType(cls);
     object_store->set_float32x4_type(type);
 
-    cls = Class::New<Int32x4>();
+    cls = Class::New<Int32x4>(isolate);
     RegisterPrivateClass(cls, Symbols::_Int32x4(), lib);
     pending_classes.Add(cls);
     object_store->set_int32x4_class(cls);
 
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, Symbols::Int32x4(), lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
     type = Type::NewNonParameterizedType(cls);
     object_store->set_int32x4_type(type);
 
-    cls = Class::New<Float64x2>();
+    cls = Class::New<Float64x2>(isolate);
     RegisterPrivateClass(cls, Symbols::_Float64x2(), lib);
     pending_classes.Add(cls);
     object_store->set_float64x2_class(cls);
 
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, Symbols::Float64x2(), lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
@@ -1767,7 +1773,7 @@
 
     // Abstract class that represents the Dart class Type.
     // Note that this class is implemented by Dart class _AbstractType.
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
     RegisterClass(cls, Symbols::Type(), core_lib);
@@ -1776,7 +1782,7 @@
     object_store->set_type_type(type);
 
     // Abstract class that represents the Dart class Function.
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
     RegisterClass(cls, Symbols::Function(), core_lib);
@@ -1784,13 +1790,13 @@
     type = Type::NewNonParameterizedType(cls);
     object_store->set_function_type(type);
 
-    cls = Class::New<Number>();
+    cls = Class::New<Number>(isolate);
     RegisterClass(cls, Symbols::Number(), core_lib);
     pending_classes.Add(cls);
     type = Type::NewNonParameterizedType(cls);
     object_store->set_number_type(type);
 
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, Symbols::Int(), core_lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
@@ -1798,7 +1804,7 @@
     type = Type::NewNonParameterizedType(cls);
     object_store->set_int_type(type);
 
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, Symbols::Double(), core_lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
@@ -1807,7 +1813,7 @@
     object_store->set_double_type(type);
 
     name = Symbols::_String().raw();
-    cls = Class::New<Instance>(kIllegalCid);
+    cls = Class::New<Instance>(kIllegalCid, isolate);
     RegisterClass(cls, name, core_lib);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
@@ -1883,7 +1889,7 @@
     }
     object_store->set_bootstrap_library(ObjectStore::kFfi, lib);
 
-    cls = Class::New<Instance>(kFfiNativeTypeCid);
+    cls = Class::New<Instance>(kFfiNativeTypeCid, isolate);
     cls.set_num_type_arguments(0);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
@@ -1891,7 +1897,7 @@
     RegisterClass(cls, Symbols::FfiNativeType(), lib);
 
 #define REGISTER_FFI_TYPE_MARKER(clazz)                                        \
-  cls = Class::New<Instance>(kFfi##clazz##Cid);                                \
+  cls = Class::New<Instance>(kFfi##clazz##Cid, isolate);                       \
   cls.set_num_type_arguments(0);                                               \
   cls.set_is_prefinalized();                                                   \
   pending_classes.Add(cls);                                                    \
@@ -1899,24 +1905,32 @@
     CLASS_LIST_FFI_TYPE_MARKER(REGISTER_FFI_TYPE_MARKER);
 #undef REGISTER_FFI_TYPE_MARKER
 
-    cls = Class::New<Instance>(kFfiNativeFunctionCid);
+    cls = Class::New<Instance>(kFfiNativeFunctionCid, isolate);
     cls.set_type_arguments_field_offset(Pointer::type_arguments_offset());
     cls.set_num_type_arguments(1);
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     RegisterClass(cls, Symbols::FfiNativeFunction(), lib);
 
-    cls = Class::NewPointerClass(kFfiPointerCid);
+    cls = Class::NewPointerClass(kFfiPointerCid, isolate);
     object_store->set_ffi_pointer_class(cls);
     pending_classes.Add(cls);
     RegisterClass(cls, Symbols::FfiPointer(), lib);
 
-    cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid);
+    cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid, isolate);
     cls.set_instance_size(DynamicLibrary::InstanceSize());
     cls.set_is_prefinalized();
     pending_classes.Add(cls);
     RegisterClass(cls, Symbols::FfiDynamicLibrary(), lib);
 
+    lib = Library::LookupLibrary(thread, Symbols::DartWasm());
+    if (lib.IsNull()) {
+      lib = Library::NewLibraryHelper(Symbols::DartWasm(), true);
+      lib.SetLoadRequested();
+      lib.Register(thread);
+    }
+    object_store->set_bootstrap_library(ObjectStore::kWasm, lib);
+
     // Finish the initialization by compiling the bootstrap scripts containing
     // the base interfaces and the implementation of the internal classes.
     const Error& error = Error::Handle(
@@ -1959,112 +1973,117 @@
     // stored in the object store. Yet we still need to create their Class
     // object so that they get put into the class_table (as a side effect of
     // Class::New()).
-    cls = Class::New<Instance>(kInstanceCid);
+    cls = Class::New<Instance>(kInstanceCid, isolate);
     object_store->set_object_class(cls);
 
-    cls = Class::New<LibraryPrefix>();
-    cls = Class::New<Type>();
-    cls = Class::New<TypeRef>();
-    cls = Class::New<TypeParameter>();
+    cls = Class::New<LibraryPrefix>(isolate);
+    cls = Class::New<Type>(isolate);
+    cls = Class::New<TypeRef>(isolate);
+    cls = Class::New<TypeParameter>(isolate);
 
-    cls = Class::New<Array>();
+    cls = Class::New<Array>(isolate);
     object_store->set_array_class(cls);
 
-    cls = Class::New<Array>(kImmutableArrayCid);
+    cls = Class::New<Array>(kImmutableArrayCid, isolate);
     object_store->set_immutable_array_class(cls);
 
-    cls = Class::New<GrowableObjectArray>();
+    cls = Class::New<GrowableObjectArray>(isolate);
     object_store->set_growable_object_array_class(cls);
 
-    cls = Class::New<LinkedHashMap>();
+    cls = Class::New<LinkedHashMap>(isolate);
     object_store->set_linked_hash_map_class(cls);
 
-    cls = Class::New<Float32x4>();
+    cls = Class::New<Float32x4>(isolate);
     object_store->set_float32x4_class(cls);
 
-    cls = Class::New<Int32x4>();
+    cls = Class::New<Int32x4>(isolate);
     object_store->set_int32x4_class(cls);
 
-    cls = Class::New<Float64x2>();
+    cls = Class::New<Float64x2>(isolate);
     object_store->set_float64x2_class(cls);
 
 #define REGISTER_TYPED_DATA_CLASS(clazz)                                       \
-  cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
+  cls = Class::NewTypedDataClass(kTypedData##clazz##Cid, isolate);
     CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
 #undef REGISTER_TYPED_DATA_CLASS
 #define REGISTER_TYPED_DATA_VIEW_CLASS(clazz)                                  \
-  cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid);
+  cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid, isolate);
     CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
 #undef REGISTER_TYPED_DATA_VIEW_CLASS
-    cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+    cls = Class::NewTypedDataViewClass(kByteDataViewCid, isolate);
 #define REGISTER_EXT_TYPED_DATA_CLASS(clazz)                                   \
-  cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);
+  cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid,       \
+                                         isolate);
     CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
 #undef REGISTER_EXT_TYPED_DATA_CLASS
 
-    cls = Class::New<Instance>(kFfiNativeTypeCid);
+    cls = Class::New<Instance>(kFfiNativeTypeCid, isolate);
     object_store->set_ffi_native_type_class(cls);
 
-#define REGISTER_FFI_CLASS(clazz) cls = Class::New<Instance>(kFfi##clazz##Cid);
+#define REGISTER_FFI_CLASS(clazz)                                              \
+  cls = Class::New<Instance>(kFfi##clazz##Cid, isolate);
     CLASS_LIST_FFI_TYPE_MARKER(REGISTER_FFI_CLASS);
 #undef REGISTER_FFI_CLASS
 
-    cls = Class::New<Instance>(kFfiNativeFunctionCid);
+    cls = Class::New<Instance>(kFfiNativeFunctionCid, isolate);
 
-    cls = Class::NewPointerClass(kFfiPointerCid);
+    cls = Class::NewPointerClass(kFfiPointerCid, isolate);
     object_store->set_ffi_pointer_class(cls);
 
-    cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid);
+    cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid, isolate);
 
-    cls = Class::New<Instance>(kByteBufferCid);
+    cls = Class::New<Instance>(kByteBufferCid, isolate,
+                               /*register_isolate=*/false);
+    cls.set_instance_size_in_words(0);
+    isolate->RegisterClass(cls);
 
-    cls = Class::New<Integer>();
+    cls = Class::New<Integer>(isolate);
     object_store->set_integer_implementation_class(cls);
 
-    cls = Class::New<Smi>();
+    cls = Class::New<Smi>(isolate);
     object_store->set_smi_class(cls);
 
-    cls = Class::New<Mint>();
+    cls = Class::New<Mint>(isolate);
     object_store->set_mint_class(cls);
 
-    cls = Class::New<Double>();
+    cls = Class::New<Double>(isolate);
     object_store->set_double_class(cls);
 
-    cls = Class::New<Closure>();
+    cls = Class::New<Closure>(isolate);
     object_store->set_closure_class(cls);
 
-    cls = Class::NewStringClass(kOneByteStringCid);
+    cls = Class::NewStringClass(kOneByteStringCid, isolate);
     object_store->set_one_byte_string_class(cls);
 
-    cls = Class::NewStringClass(kTwoByteStringCid);
+    cls = Class::NewStringClass(kTwoByteStringCid, isolate);
     object_store->set_two_byte_string_class(cls);
 
-    cls = Class::NewStringClass(kExternalOneByteStringCid);
+    cls = Class::NewStringClass(kExternalOneByteStringCid, isolate);
     object_store->set_external_one_byte_string_class(cls);
 
-    cls = Class::NewStringClass(kExternalTwoByteStringCid);
+    cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate);
     object_store->set_external_two_byte_string_class(cls);
 
-    cls = Class::New<Bool>();
+    cls = Class::New<Bool>(isolate);
     object_store->set_bool_class(cls);
 
-    cls = Class::New<Instance>(kNullCid);
+    cls = Class::New<Instance>(kNullCid, isolate);
     object_store->set_null_class(cls);
 
-    cls = Class::New<Capability>();
-    cls = Class::New<ReceivePort>();
-    cls = Class::New<SendPort>();
-    cls = Class::New<StackTrace>();
-    cls = Class::New<RegExp>();
-    cls = Class::New<Number>();
+    cls = Class::New<Capability>(isolate);
+    cls = Class::New<ReceivePort>(isolate);
+    cls = Class::New<SendPort>(isolate);
+    cls = Class::New<StackTrace>(isolate);
+    cls = Class::New<RegExp>(isolate);
+    cls = Class::New<Number>(isolate);
 
-    cls = Class::New<WeakProperty>();
+    cls = Class::New<WeakProperty>(isolate);
     object_store->set_weak_property_class(cls);
 
-    cls = Class::New<MirrorReference>();
-    cls = Class::New<UserTag>();
+    cls = Class::New<MirrorReference>(isolate);
+    cls = Class::New<UserTag>(isolate);
 
-    cls = Class::New<TransferableTypedData>();
+    cls = Class::New<TransferableTypedData>(isolate);
   }
   return Error::null();
 }
@@ -2312,7 +2331,7 @@
 }
 
 template <class FakeObject>
-RawClass* Class::New() {
+RawClass* Class::New(Isolate* isolate, bool register_class) {
   ASSERT(Object::class_class() != Class::null());
   Class& result = Class::Handle();
   {
@@ -2348,7 +2367,9 @@
   NOT_IN_PRECOMPILED(result.set_is_declared_in_bytecode(false));
   NOT_IN_PRECOMPILED(result.set_binary_declaration_offset(0));
   result.InitEmptyFields();
-  Isolate::Current()->RegisterClass(result);
+  if (register_class) {
+    isolate->RegisterClass(result);
+  }
   return result.raw();
 }
 
@@ -2977,7 +2998,7 @@
   // Initialize signature: receiver is a single fixed parameter.
   const intptr_t kNumParameters = 1;
   extractor.set_num_fixed_parameters(kNumParameters);
-  extractor.SetNumOptionalParameters(0, 0);
+  extractor.SetNumOptionalParameters(0, false);
   extractor.set_parameter_types(Object::extractor_parameter_types());
   extractor.set_parameter_names(Object::extractor_parameter_names());
   extractor.set_result_type(Object::dynamic_type());
@@ -3727,9 +3748,11 @@
 }
 
 template <class FakeInstance>
-RawClass* Class::New(intptr_t index) {
+RawClass* Class::New(intptr_t index, Isolate* isolate, bool register_class) {
   Class& result = Class::Handle(NewCommon<FakeInstance>(index));
-  Isolate::Current()->RegisterClass(result);
+  if (register_class) {
+    isolate->RegisterClass(result);
+  }
   return result.raw();
 }
 
@@ -3743,6 +3766,12 @@
   result.set_name(name);
   result.set_script(script);
   result.set_token_pos(token_pos);
+
+  // The size gets initialized to 0. Once the class gets finalized the class
+  // finalizer will set the correct size.
+  ASSERT(!result.is_finalized() && !result.is_prefinalized());
+  result.set_instance_size_in_words(0);
+
   if (register_class) {
     Isolate::Current()->RegisterClass(result);
   }
@@ -3750,7 +3779,7 @@
 }
 
 RawClass* Class::NewInstanceClass() {
-  return Class::New<Instance>(kIllegalCid);
+  return Class::New<Instance>(kIllegalCid, Isolate::Current());
 }
 
 RawClass* Class::NewNativeWrapper(const Library& library,
@@ -3780,7 +3809,7 @@
   }
 }
 
-RawClass* Class::NewStringClass(intptr_t class_id) {
+RawClass* Class::NewStringClass(intptr_t class_id, Isolate* isolate) {
   intptr_t instance_size;
   if (class_id == kOneByteStringCid) {
     instance_size = OneByteString::InstanceSize();
@@ -3792,51 +3821,62 @@
     ASSERT(class_id == kExternalTwoByteStringCid);
     instance_size = ExternalTwoByteString::InstanceSize();
   }
-  Class& result = Class::Handle(New<String>(class_id));
+  Class& result =
+      Class::Handle(New<String>(class_id, isolate, /*register_class=*/false));
   result.set_instance_size(instance_size);
   result.set_next_field_offset(String::NextFieldOffset());
   result.set_is_prefinalized();
+  isolate->RegisterClass(result);
   return result.raw();
 }
 
-RawClass* Class::NewTypedDataClass(intptr_t class_id) {
+RawClass* Class::NewTypedDataClass(intptr_t class_id, Isolate* isolate) {
   ASSERT(RawObject::IsTypedDataClassId(class_id));
   intptr_t instance_size = TypedData::InstanceSize();
-  Class& result = Class::Handle(New<TypedData>(class_id));
+  Class& result = Class::Handle(
+      New<TypedData>(class_id, isolate, /*register_class=*/false));
   result.set_instance_size(instance_size);
   result.set_next_field_offset(TypedData::NextFieldOffset());
   result.set_is_prefinalized();
+  isolate->RegisterClass(result);
   return result.raw();
 }
 
-RawClass* Class::NewTypedDataViewClass(intptr_t class_id) {
+RawClass* Class::NewTypedDataViewClass(intptr_t class_id, Isolate* isolate) {
   ASSERT(RawObject::IsTypedDataViewClassId(class_id));
   const intptr_t instance_size = TypedDataView::InstanceSize();
-  Class& result = Class::Handle(New<TypedDataView>(class_id));
+  Class& result = Class::Handle(
+      New<TypedDataView>(class_id, isolate, /*register_class=*/false));
   result.set_instance_size(instance_size);
   result.set_next_field_offset(TypedDataView::NextFieldOffset());
   result.set_is_prefinalized();
+  isolate->RegisterClass(result);
   return result.raw();
 }
 
-RawClass* Class::NewExternalTypedDataClass(intptr_t class_id) {
+RawClass* Class::NewExternalTypedDataClass(intptr_t class_id,
+                                           Isolate* isolate) {
   ASSERT(RawObject::IsExternalTypedDataClassId(class_id));
   intptr_t instance_size = ExternalTypedData::InstanceSize();
-  Class& result = Class::Handle(New<ExternalTypedData>(class_id));
+  Class& result = Class::Handle(
+      New<ExternalTypedData>(class_id, isolate, /*register_class=*/false));
   result.set_instance_size(instance_size);
   result.set_next_field_offset(ExternalTypedData::NextFieldOffset());
   result.set_is_prefinalized();
+  isolate->RegisterClass(result);
   return result.raw();
 }
 
-RawClass* Class::NewPointerClass(intptr_t class_id) {
+RawClass* Class::NewPointerClass(intptr_t class_id, Isolate* isolate) {
   ASSERT(RawObject::IsFfiPointerClassId(class_id));
   intptr_t instance_size = Pointer::InstanceSize();
-  Class& result = Class::Handle(New<Pointer>(class_id));
+  Class& result =
+      Class::Handle(New<Pointer>(class_id, isolate, /*register_class=*/false));
   result.set_instance_size(instance_size);
   result.set_type_arguments_field_offset(Pointer::type_arguments_offset());
   result.set_next_field_offset(Pointer::NextFieldOffset());
   result.set_is_prefinalized();
+  isolate->RegisterClass(result);
   return result.raw();
 }
 
@@ -6202,66 +6242,7 @@
 }
 
 const char* Function::KindToCString(RawFunction::Kind kind) {
-  switch (kind) {
-    case RawFunction::kRegularFunction:
-      return "RegularFunction";
-      break;
-    case RawFunction::kClosureFunction:
-      return "ClosureFunction";
-      break;
-    case RawFunction::kImplicitClosureFunction:
-      return "ImplicitClosureFunction";
-      break;
-    case RawFunction::kSignatureFunction:
-      return "SignatureFunction";
-      break;
-    case RawFunction::kGetterFunction:
-      return "GetterFunction";
-      break;
-    case RawFunction::kSetterFunction:
-      return "SetterFunction";
-      break;
-    case RawFunction::kConstructor:
-      return "Constructor";
-      break;
-    case RawFunction::kImplicitGetter:
-      return "ImplicitGetter";
-      break;
-    case RawFunction::kImplicitSetter:
-      return "ImplicitSetter";
-      break;
-    case RawFunction::kImplicitStaticGetter:
-      return "ImplicitStaticGetter";
-      break;
-    case RawFunction::kFieldInitializer:
-      return "FieldInitializer";
-      break;
-    case RawFunction::kMethodExtractor:
-      return "MethodExtractor";
-      break;
-    case RawFunction::kNoSuchMethodDispatcher:
-      return "NoSuchMethodDispatcher";
-      break;
-    case RawFunction::kInvokeFieldDispatcher:
-      return "InvokeFieldDispatcher";
-      break;
-    case RawFunction::kIrregexpFunction:
-      return "IrregexpFunction";
-      break;
-    case RawFunction::kDynamicInvocationForwarder:
-      return "DynamicInvocationForwarder";
-      break;
-    case RawFunction::kFfiTrampoline:
-      return "FfiTrampoline";
-      break;
-  }
-  // When you add a case to this switch, please also update the observatory.
-  // - runtime/observatory/lib/src/models/objects/function.dart (FunctionKind)
-  // - runtime/observatory/lib/src/elements/function_view.dart
-  //   (_functionKindToString)
-  // - runtime/observatory/lib/src/service/object.dart (stringToFunctionKind)
-  UNREACHABLE();
-  return NULL;
+  return RawFunction::KindToCString(kind);
 }
 
 void Function::SetRedirectionType(const Type& type) const {
@@ -7362,6 +7343,13 @@
     // in new space.
     ASSERT(space == Heap::kOld);
   }
+
+  // Force-optimized functions are not debuggable because they cannot
+  // deoptimize.
+  if (result.ForceOptimize()) {
+    result.set_is_debuggable(false);
+  }
+
   return result.raw();
 }
 
@@ -9978,60 +9966,6 @@
   StoreNonPointer(&raw_ptr()->load_state_, RawLibrary::kLoaded);
 }
 
-void Library::SetLoadError(const Instance& error) const {
-  // Should not be already successfully loaded or just allocated.
-  ASSERT(LoadInProgress() || LoadRequested() || LoadFailed());
-  StoreNonPointer(&raw_ptr()->load_state_, RawLibrary::kLoadError);
-  StorePointer(&raw_ptr()->load_error_, error.raw());
-}
-
-// Traits for looking up Libraries by url in a hash set.
-class LibraryUrlTraits {
- public:
-  static const char* Name() { return "LibraryUrlTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(a.IsLibrary() && b.IsLibrary());
-    // Library objects are always canonical.
-    return a.raw() == b.raw();
-  }
-  static uword Hash(const Object& key) { return Library::Cast(key).UrlHash(); }
-};
-typedef UnorderedHashSet<LibraryUrlTraits> LibraryLoadErrorSet;
-
-RawInstance* Library::TransitiveLoadError() const {
-  if (LoadError() != Instance::null()) {
-    return LoadError();
-  }
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  Zone* zone = thread->zone();
-  ObjectStore* object_store = isolate->object_store();
-  LibraryLoadErrorSet set(object_store->library_load_error_table());
-  bool present = false;
-  if (set.GetOrNull(*this, &present) != Object::null()) {
-    object_store->set_library_load_error_table(set.Release());
-    return Instance::null();
-  }
-  // Ensure we don't repeatedly visit the same library again.
-  set.Insert(*this);
-  object_store->set_library_load_error_table(set.Release());
-  intptr_t num_imp = num_imports();
-  Library& lib = Library::Handle(zone);
-  Instance& error = Instance::Handle(zone);
-  for (intptr_t i = 0; i < num_imp; i++) {
-    HANDLESCOPE(thread);
-    lib = ImportLibraryAt(i);
-    error = lib.TransitiveLoadError();
-    if (!error.IsNull()) {
-      break;
-    }
-  }
-  return error.raw();
-}
-
 static RawString* MakeClassMetaName(Thread* thread,
                                     Zone* zone,
                                     const Class& cls) {
@@ -10224,6 +10158,14 @@
       !obj.IsLibrary() && !obj.IsTypeParameter()) {
     UNREACHABLE();
   }
+  if (obj.IsLibrary()) {
+    // Ensure top-level class is loaded as it may contain annotations of
+    // a library.
+    const auto& cls = Class::Handle(toplevel_class());
+    if (!cls.IsNull()) {
+      cls.EnsureDeclarationLoaded();
+    }
+  }
   const String& metaname = String::Handle(MakeMetadataName(obj));
   Field& field = Field::Handle(GetMetadataField(metaname));
   if (field.IsNull()) {
@@ -10240,11 +10182,17 @@
       metadata = kernel::EvaluateMetadata(
           field, /* is_annotations_offset = */ obj.IsLibrary());
     }
-    if (metadata.IsArray()) {
-      ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
-      field.SetStaticValue(Array::Cast(metadata), true);
+    if (metadata.IsArray() || metadata.IsNull()) {
+      ASSERT(metadata.raw() != Object::empty_array().raw());
+      field.SetStaticValue(
+          metadata.IsNull() ? Object::null_array() : Array::Cast(metadata),
+          true);
     }
   }
+  if (metadata.IsNull()) {
+    // Metadata field exists in order to reference extended metadata.
+    return Object::empty_array().raw();
+  }
   return metadata.raw();
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 }
@@ -10254,9 +10202,7 @@
 #if defined(DART_PRECOMPILED_RUNTIME)
   return Object::empty_array().raw();
 #else
-  if (!obj.IsFunction()) {
-    UNREACHABLE();
-  }
+  RELEASE_ASSERT(obj.IsFunction() || obj.IsLibrary());
   const String& metaname = String::Handle(MakeMetadataName(obj));
   Field& field = Field::Handle(GetMetadataField(metaname));
   if (field.IsNull()) {
@@ -11095,7 +11041,6 @@
   result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
   result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
   result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
-  result.StorePointer(&result.raw_ptr()->load_error_, Instance::null());
   result.set_native_entry_resolver(NULL);
   result.set_native_entry_symbol_resolver(NULL);
   result.set_is_in_fullsnapshot(false);
@@ -11726,6 +11671,10 @@
   return Isolate::Current()->object_store()->_vmservice_library();
 }
 
+RawLibrary* Library::WasmLibrary() {
+  return Isolate::Current()->object_store()->wasm_library();
+}
+
 const char* Library::ToCString() const {
   const String& name = String::Handle(url());
   return OS::SCreate(Thread::Current()->zone(), "Library:'%s'",
@@ -11742,49 +11691,6 @@
   return Library::null();
 }
 
-RawInstance* LibraryPrefix::LoadError() const {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  Zone* zone = thread->zone();
-  ObjectStore* object_store = isolate->object_store();
-  GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(zone, object_store->libraries());
-  ASSERT(!libs.IsNull());
-  LibraryLoadErrorSet set(HashTables::New<LibraryLoadErrorSet>(libs.Length()));
-  object_store->set_library_load_error_table(set.Release());
-  Library& lib = Library::Handle(zone);
-  Instance& error = Instance::Handle(zone);
-  for (int32_t i = 0; i < num_imports(); i++) {
-    lib = GetLibrary(i);
-    ASSERT(!lib.IsNull());
-    HANDLESCOPE(thread);
-    error = lib.TransitiveLoadError();
-    if (!error.IsNull()) {
-      break;
-    }
-  }
-  object_store->set_library_load_error_table(Object::empty_array());
-  return error.raw();
-}
-
-bool LibraryPrefix::ContainsLibrary(const Library& library) const {
-  int32_t num_current_imports = num_imports();
-  if (num_current_imports > 0) {
-    Library& lib = Library::Handle();
-    const String& url = String::Handle(library.url());
-    String& lib_url = String::Handle();
-    for (int32_t i = 0; i < num_current_imports; i++) {
-      lib = GetLibrary(i);
-      ASSERT(!lib.IsNull());
-      lib_url = lib.url();
-      if (url.Equals(lib_url)) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 void LibraryPrefix::AddImport(const Namespace& import) const {
   intptr_t num_current_imports = num_imports();
 
@@ -11805,9 +11711,6 @@
 }
 
 RawObject* LibraryPrefix::LookupObject(const String& name) const {
-  if (!is_loaded() && !FLAG_load_deferred_eagerly) {
-    return Object::null();
-  }
   Array& imports = Array::Handle(this->imports());
   Object& obj = Object::Handle();
   Namespace& import = Namespace::Handle();
@@ -11876,116 +11779,6 @@
   return Class::null();
 }
 
-void LibraryPrefix::set_is_loaded() const {
-  StoreNonPointer(&raw_ptr()->is_loaded_, true);
-}
-
-bool LibraryPrefix::LoadLibrary() const {
-  // Non-deferred prefixes are loaded.
-  ASSERT(is_deferred_load() || is_loaded());
-  if (is_loaded()) {
-    return true;  // Load request has already completed.
-  }
-  ASSERT(is_deferred_load());
-  ASSERT(num_imports() == 1);
-  if (Dart::vm_snapshot_kind() == Snapshot::kFullAOT) {
-    // The library list was tree-shaken away.
-    this->set_is_loaded();
-    return true;
-  }
-  // This is a prefix for a deferred library. If the library is not loaded
-  // yet and isn't being loaded, call the library tag handler to schedule
-  // loading. Once all outstanding load requests have completed, the embedder
-  // will call the core library to:
-  // - invalidate dependent code of this prefix;
-  // - mark this prefixes as loaded;
-  // - complete the future associated with this prefix.
-  const Library& deferred_lib = Library::Handle(GetLibrary(0));
-  if (deferred_lib.Loaded()) {
-    this->set_is_loaded();
-    return true;
-  } else if (deferred_lib.LoadNotStarted()) {
-    Thread* thread = Thread::Current();
-    Isolate* isolate = thread->isolate();
-    Zone* zone = thread->zone();
-    deferred_lib.SetLoadRequested();
-    const GrowableObjectArray& pending_deferred_loads =
-        GrowableObjectArray::Handle(
-            isolate->object_store()->pending_deferred_loads());
-    pending_deferred_loads.Add(deferred_lib);
-    const String& lib_url = String::Handle(zone, deferred_lib.url());
-    const Object& obj = Object::Handle(
-        zone, isolate->CallTagHandler(
-                  Dart_kImportTag, Library::Handle(zone, importer()), lib_url));
-    if (obj.IsError()) {
-      Exceptions::PropagateError(Error::Cast(obj));
-    }
-  } else {
-    // Another load request is in flight or previously failed.
-    ASSERT(deferred_lib.LoadRequested() || deferred_lib.LoadFailed());
-  }
-  return false;  // Load request not yet completed.
-}
-
-RawArray* LibraryPrefix::dependent_code() const {
-  return raw_ptr()->dependent_code_;
-}
-
-void LibraryPrefix::set_dependent_code(const Array& array) const {
-  StorePointer(&raw_ptr()->dependent_code_, array.raw());
-}
-
-class PrefixDependentArray : public WeakCodeReferences {
- public:
-  explicit PrefixDependentArray(const LibraryPrefix& prefix)
-      : WeakCodeReferences(Array::Handle(prefix.dependent_code())),
-        prefix_(prefix) {}
-
-  virtual void UpdateArrayTo(const Array& value) {
-    prefix_.set_dependent_code(value);
-  }
-
-  virtual void ReportDeoptimization(const Code& code) {
-    // This gets called when the code object is on the stack
-    // while nuking code that depends on a prefix. We don't expect
-    // this to happen, so make sure we die loudly if we find
-    // ourselves here.
-    UNIMPLEMENTED();
-  }
-
-  virtual void ReportSwitchingCode(const Code& code) {
-    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
-      THR_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
-                String::Handle(prefix_.name()).ToCString(),
-                code.is_optimized() ? "optimized" : "unoptimized",
-                code.IsDisabled() ? "'patched'" : "'unpatched'",
-                Function::Handle(code.function()).ToCString());
-    }
-  }
-
- private:
-  const LibraryPrefix& prefix_;
-  DISALLOW_COPY_AND_ASSIGN(PrefixDependentArray);
-};
-
-void LibraryPrefix::RegisterDependentCode(const Code& code) const {
-  ASSERT(is_deferred_load());
-  // In background compilation, a library can be loaded while we are compiling.
-  // The generated code will be rejected in that case,
-  ASSERT(!is_loaded() || Compiler::IsBackgroundCompilation());
-  PrefixDependentArray a(*this);
-  a.Register(code);
-}
-
-void LibraryPrefix::InvalidateDependentCode() const {
-  PrefixDependentArray a(*this);
-  if (FLAG_trace_deoptimization && a.HasCodes()) {
-    THR_Print("Deopt for lazy load (prefix %s)\n", ToCString());
-  }
-  a.DisableCode();
-  set_is_loaded();
-}
-
 RawLibraryPrefix* LibraryPrefix::New() {
   RawObject* raw = Object::Allocate(LibraryPrefix::kClassId,
                                     LibraryPrefix::InstanceSize(), Heap::kOld);
@@ -12001,7 +11794,6 @@
   result.set_num_imports(0);
   result.set_importer(importer);
   result.StoreNonPointer(&result.raw_ptr()->is_deferred_load_, deferred_load);
-  result.StoreNonPointer(&result.raw_ptr()->is_loaded_, !deferred_load);
   result.set_imports(Array::Handle(Array::New(kInitialSize)));
   result.AddImport(import);
   return result.raw();
@@ -12635,8 +12427,8 @@
     result ^= raw;
     result.SetSize(size);
     result.SetHasSingleEntryPoint(has_single_entry_point);
-    result.set_stats(nullptr);
     result.set_unchecked_entrypoint_pc_offset(unchecked_entrypoint_pc_offset);
+    result.set_stats(nullptr);
   }
   return result.raw();
 }
@@ -12839,6 +12631,8 @@
       return "osr-entry    ";
     case RawPcDescriptors::kRewind:
       return "rewind       ";
+    case RawPcDescriptors::kBSSRelocation:
+      return "bss reloc    ";
     case RawPcDescriptors::kOther:
       return "other        ";
     case RawPcDescriptors::kAnyKind:
@@ -12963,7 +12757,7 @@
   int bit_remainder = bit_index & (kBitsPerByte - 1);
   uint8_t byte_mask = 1U << bit_remainder;
   uint8_t byte = raw_ptr()->data()[byte_index];
-  return (byte & byte_mask);
+  return (byte & byte_mask) != 0;
 }
 
 void StackMap::SetBit(intptr_t bit_index, bool value) const {
@@ -13227,9 +13021,9 @@
   ASSERT((handler_pc_offset == static_cast<uword>(kMaxUint32)) ||
          (handler_pc_offset < static_cast<uword>(kMaxUint32)));
   info->handler_pc_offset = handler_pc_offset;
-  info->needs_stacktrace = needs_stacktrace;
-  info->has_catch_all = has_catch_all;
-  info->is_generated = is_generated;
+  info->needs_stacktrace = static_cast<int8_t>(needs_stacktrace);
+  info->has_catch_all = static_cast<int8_t>(has_catch_all);
+  info->is_generated = static_cast<int8_t>(is_generated);
 }
 
 void ExceptionHandlers::GetHandlerInfo(intptr_t try_index,
@@ -13251,17 +13045,17 @@
 
 bool ExceptionHandlers::NeedsStackTrace(intptr_t try_index) const {
   ASSERT((try_index >= 0) && (try_index < num_entries()));
-  return raw_ptr()->data()[try_index].needs_stacktrace;
+  return raw_ptr()->data()[try_index].needs_stacktrace != 0;
 }
 
 bool ExceptionHandlers::IsGenerated(intptr_t try_index) const {
   ASSERT((try_index >= 0) && (try_index < num_entries()));
-  return raw_ptr()->data()[try_index].is_generated;
+  return raw_ptr()->data()[try_index].is_generated != 0;
 }
 
 bool ExceptionHandlers::HasCatchAll(intptr_t try_index) const {
   ASSERT((try_index >= 0) && (try_index < num_entries()));
-  return raw_ptr()->data()[try_index].has_catch_all;
+  return raw_ptr()->data()[try_index].has_catch_all != 0;
 }
 
 void ExceptionHandlers::SetHandledTypes(intptr_t try_index,
@@ -13348,7 +13142,7 @@
         handled_types.IsNull() ? 0 : handled_types.Length();
     len += Utils::SNPrint(NULL, 0, FORMAT1, i, info.handler_pc_offset,
                           num_types, info.outer_try_index,
-                          info.is_generated ? "(generated)" : "");
+                          info.is_generated != 0 ? "(generated)" : "");
     for (int k = 0; k < num_types; k++) {
       type ^= handled_types.At(k);
       ASSERT(!type.IsNull());
@@ -13367,7 +13161,7 @@
     num_chars +=
         Utils::SNPrint((buffer + num_chars), (len - num_chars), FORMAT1, i,
                        info.handler_pc_offset, num_types, info.outer_try_index,
-                       info.is_generated ? "(generated)" : "");
+                       info.is_generated != 0 ? "(generated)" : "");
     for (int k = 0; k < num_types; k++) {
       type ^= handled_types.At(k);
       num_chars += Utils::SNPrint((buffer + num_chars), (len - num_chars),
@@ -13592,6 +13386,29 @@
   }
 }
 
+const char* ICData::RebindRuleToCString(RebindRule r) {
+  switch (r) {
+#define RULE_CASE(Name)                                                        \
+  case RebindRule::k##Name:                                                    \
+    return #Name;
+    FOR_EACH_REBIND_RULE(RULE_CASE)
+#undef RULE_CASE
+    default:
+      return nullptr;
+  }
+}
+
+bool ICData::RebindRuleFromCString(const char* str, RebindRule* out) {
+#define RULE_CASE(Name)                                                        \
+  if (strcmp(str, #Name) == 0) {                                               \
+    *out = RebindRule::k##Name;                                                \
+    return true;                                                               \
+  }
+  FOR_EACH_REBIND_RULE(RULE_CASE)
+#undef RULE_CASE
+  return false;
+}
+
 ICData::RebindRule ICData::rebind_rule() const {
   return (ICData::RebindRule)RebindRuleBits::decode(raw_ptr()->state_bits_);
 }
@@ -14333,59 +14150,6 @@
   }
   return false;
 }
-
-// Returns true if all targets are the same.
-// TODO(srdjan): if targets are native use their C_function to compare.
-// TODO(rmacnak): this question should only be asked against a CallTargets,
-// not an ICData.
-bool ICData::HasOneTarget() const {
-  ASSERT(!NumberOfChecksIs(0));
-  const Function& first_target = Function::Handle(GetTargetAt(0));
-  const intptr_t len = NumberOfChecks();
-  for (intptr_t i = 1; i < len; i++) {
-    if (IsUsedAt(i) && (GetTargetAt(i) != first_target.raw())) {
-      return false;
-    }
-  }
-  if (is_megamorphic()) {
-    Thread* thread = Thread::Current();
-    Zone* zone = thread->zone();
-    const String& name = String::Handle(zone, target_name());
-    const Array& descriptor = Array::Handle(zone, arguments_descriptor());
-    const MegamorphicCache& cache = MegamorphicCache::Handle(
-        zone, MegamorphicCacheTable::LookupClone(thread, name, descriptor));
-    MegamorphicCacheEntries entries(Array::Handle(cache.buckets()));
-    for (intptr_t i = 0; i < entries.Length(); i++) {
-      const intptr_t id =
-          Smi::Value(entries[i].Get<MegamorphicCache::kClassIdIndex>());
-      if (id == kIllegalCid) {
-        continue;
-      }
-      if (entries[i].Get<MegamorphicCache::kTargetFunctionIndex>() !=
-          first_target.raw()) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-void ICData::GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
-                                   GrowableArray<intptr_t>* second) const {
-  ASSERT(NumArgsTested() == 2);
-  first->Clear();
-  second->Clear();
-  GrowableArray<intptr_t> class_ids;
-  const intptr_t len = NumberOfChecks();
-  for (intptr_t i = 0; i < len; i++) {
-    if (GetCountAt(i) > 0) {
-      GetClassIdsAt(i, &class_ids);
-      ASSERT(class_ids.length() == 2);
-      first->Add(class_ids[0]);
-      second->Add(class_ids[1]);
-    }
-  }
-}
 #endif
 
 bool ICData::IsUsedAt(intptr_t i) const {
@@ -14517,6 +14281,9 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 RawICData* ICData::NewFrom(const ICData& from, intptr_t num_args_tested) {
+  // See comment in [ICData::Clone] why we access the megamorphic bit first.
+  const bool is_megamorphic = from.is_megamorphic();
+
   const ICData& result = ICData::Handle(ICData::New(
       Function::Handle(from.Owner()), String::Handle(from.target_name()),
       Array::Handle(from.arguments_descriptor()), from.deopt_id(),
@@ -14524,12 +14291,21 @@
       AbstractType::Handle(from.receivers_static_type())));
   // Copy deoptimization reasons.
   result.SetDeoptReasons(from.DeoptReasons());
-  result.set_is_megamorphic(from.is_megamorphic());
+  result.set_is_megamorphic(is_megamorphic);
   return result.raw();
 }
 
 RawICData* ICData::Clone(const ICData& from) {
   Zone* zone = Thread::Current()->zone();
+
+  // We have to check the megamorphic bit before accessing the entries of the
+  // ICData to ensure all writes to the entries have been flushed and are
+  // visible at this point.
+  //
+  // This will allow us to maintain the invariant that if the megamorphic bit is
+  // set, the number of entries in the ICData have reached the limit.
+  const bool is_megamorphic = from.is_megamorphic();
+
   const ICData& result = ICData::Handle(
       zone, ICData::NewDescriptor(
                 zone, Function::Handle(zone, from.Owner()),
@@ -14549,7 +14325,11 @@
   result.set_entries(cloned_array);
   // Copy deoptimization reasons.
   result.SetDeoptReasons(from.DeoptReasons());
-  result.set_is_megamorphic(from.is_megamorphic());
+  result.set_is_megamorphic(is_megamorphic);
+
+  RELEASE_ASSERT(!is_megamorphic ||
+                 result.NumberOfChecks() >= FLAG_max_polymorphic_checks);
+
   return result.raw();
 }
 #endif
@@ -15378,6 +15158,25 @@
   reader.DumpSourcePositions(PayloadStart());
 }
 
+bool Code::VerifyBSSRelocations() const {
+  const auto& descriptors = PcDescriptors::Handle(pc_descriptors());
+  const auto& insns = Instructions::Handle(instructions());
+  PcDescriptors::Iterator iterator(descriptors,
+                                   RawPcDescriptors::kBSSRelocation);
+  while (iterator.MoveNext()) {
+    const uword reloc = insns.PayloadStart() + iterator.PcOffset();
+    const word target = *reinterpret_cast<word*>(reloc);
+    // The relocation is in its original unpatched form -- the addend
+    // representing the target symbol itself.
+    if (target >= 0 &&
+        target <
+            BSS::RelocationIndex(BSS::Relocation::NumRelocations) * kWordSize) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void Bytecode::Disassemble(DisassemblyFormatter* formatter) const {
 #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -15413,9 +15212,7 @@
     result.set_pc_descriptors(Object::empty_descriptors());
     result.set_instructions_binary_offset(instructions_offset);
     result.set_source_positions_binary_offset(0);
-#if !defined(PRODUCT)
     result.set_local_variables_binary_offset(0);
-#endif
   }
   return result.raw();
 }
@@ -15973,37 +15770,6 @@
   }
 }
 
-RawMegamorphicCache* MegamorphicCache::Clone(const MegamorphicCache& from) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  MegamorphicCache& result = MegamorphicCache::Handle(zone);
-  {
-    RawObject* raw =
-        Object::Allocate(MegamorphicCache::kClassId,
-                         MegamorphicCache::InstanceSize(), Heap::kNew);
-    NoSafepointScope no_safepoint;
-    result ^= raw;
-  }
-
-  SafepointMutexLocker ml(thread->isolate()->megamorphic_mutex());
-  const Array& from_buckets = Array::Handle(zone, from.buckets());
-  const intptr_t len = from_buckets.Length();
-  const Array& cloned_buckets =
-      Array::Handle(zone, Array::New(len, Heap::kNew));
-  Object& obj = Object::Handle(zone);
-  for (intptr_t i = 0; i < len; i++) {
-    obj = from_buckets.At(i);
-    cloned_buckets.SetAt(i, obj);
-  }
-  result.set_buckets(cloned_buckets);
-  result.set_mask(from.mask());
-  result.set_target_name(String::Handle(zone, from.target_name()));
-  result.set_arguments_descriptor(
-      Array::Handle(zone, from.arguments_descriptor()));
-  result.set_filled_entry_count(from.filled_entry_count());
-  return result.raw();
-}
-
 void SubtypeTestCache::Init() {
   cached_array_ = Array::New(kTestEntryLength, Heap::kOld);
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index bea9d0a..37aba42 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -78,48 +78,46 @@
   using RawObjectType = Raw##object;                                           \
   Raw##object* raw() const { return reinterpret_cast<Raw##object*>(raw_); }    \
   bool Is##object() const { return true; }                                     \
-  static object& Handle(Zone* zone, Raw##object* raw_ptr) {                    \
-    object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone));  \
-    initializeHandle(obj, raw_ptr);                                            \
-    return *obj;                                                               \
+  DART_NOINLINE static object& Handle() {                                      \
+    return HandleImpl(Thread::Current()->zone(), object::null());              \
   }                                                                            \
-  static object& Handle() {                                                    \
-    return Handle(Thread::Current()->zone(), object::null());                  \
+  DART_NOINLINE static object& Handle(Zone* zone) {                            \
+    return HandleImpl(zone, object::null());                                   \
   }                                                                            \
-  static object& Handle(Zone* zone) { return Handle(zone, object::null()); }   \
-  static object& Handle(Raw##object* raw_ptr) {                                \
-    return Handle(Thread::Current()->zone(), raw_ptr);                         \
+  DART_NOINLINE static object& Handle(Raw##object* raw_ptr) {                  \
+    return HandleImpl(Thread::Current()->zone(), raw_ptr);                     \
   }                                                                            \
-  static object& CheckedHandle(Zone* zone, RawObject* raw_ptr) {               \
-    object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone));  \
-    initializeHandle(obj, raw_ptr);                                            \
-    if (!obj->Is##object()) {                                                  \
-      FATAL2("Handle check failed: saw %s expected %s", obj->ToCString(),      \
-             #object);                                                         \
-    }                                                                          \
-    return *obj;                                                               \
+  DART_NOINLINE static object& Handle(Zone* zone, Raw##object* raw_ptr) {      \
+    return HandleImpl(zone, raw_ptr);                                          \
   }                                                                            \
-  static object& ZoneHandle(Zone* zone, Raw##object* raw_ptr) {                \
-    object* obj =                                                              \
-        reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone));        \
-    initializeHandle(obj, raw_ptr);                                            \
-    return *obj;                                                               \
+  DART_NOINLINE static object& ZoneHandle() {                                  \
+    return ZoneHandleImpl(Thread::Current()->zone(), object::null());          \
   }                                                                            \
-  static object* ReadOnlyHandle() {                                            \
+  DART_NOINLINE static object& ZoneHandle(Zone* zone) {                        \
+    return ZoneHandleImpl(zone, object::null());                               \
+  }                                                                            \
+  DART_NOINLINE static object& ZoneHandle(Raw##object* raw_ptr) {              \
+    return ZoneHandleImpl(Thread::Current()->zone(), raw_ptr);                 \
+  }                                                                            \
+  DART_NOINLINE static object& ZoneHandle(Zone* zone, Raw##object* raw_ptr) {  \
+    return ZoneHandleImpl(zone, raw_ptr);                                      \
+  }                                                                            \
+  DART_NOINLINE static object* ReadOnlyHandle() {                              \
     object* obj = reinterpret_cast<object*>(Dart::AllocateReadOnlyHandle());   \
     initializeHandle(obj, object::null());                                     \
     return obj;                                                                \
   }                                                                            \
-  static object& ZoneHandle(Zone* zone) {                                      \
-    return ZoneHandle(zone, object::null());                                   \
+  DART_NOINLINE static object& CheckedHandle(Zone* zone, RawObject* raw_ptr) { \
+    object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone));  \
+    initializeHandle(obj, raw_ptr);                                            \
+    if (!obj->Is##object()) {                                                  \
+      FATAL2("Handle check failed: saw %s expected %s", obj->ToCString(),      \
+             #object);                                                         \
+    }                                                                          \
+    return *obj;                                                               \
   }                                                                            \
-  static object& ZoneHandle() {                                                \
-    return ZoneHandle(Thread::Current()->zone(), object::null());              \
-  }                                                                            \
-  static object& ZoneHandle(Raw##object* raw_ptr) {                            \
-    return ZoneHandle(Thread::Current()->zone(), raw_ptr);                     \
-  }                                                                            \
-  static object& CheckedZoneHandle(Zone* zone, RawObject* raw_ptr) {           \
+  DART_NOINLINE static object& CheckedZoneHandle(Zone* zone,                   \
+                                                 RawObject* raw_ptr) {         \
     object* obj =                                                              \
         reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone));        \
     initializeHandle(obj, raw_ptr);                                            \
@@ -129,7 +127,7 @@
     }                                                                          \
     return *obj;                                                               \
   }                                                                            \
-  static object& CheckedZoneHandle(RawObject* raw_ptr) {                       \
+  DART_NOINLINE static object& CheckedZoneHandle(RawObject* raw_ptr) {         \
     return CheckedZoneHandle(Thread::Current()->zone(), raw_ptr);              \
   }                                                                            \
   /* T::Cast cannot be applied to a null Object, because the object vtable */  \
@@ -150,6 +148,17 @@
   static const ClassId kClassId = k##object##Cid;                              \
                                                                                \
  private: /* NOLINT */                                                         \
+  static object& HandleImpl(Zone* zone, Raw##object* raw_ptr) {                \
+    object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone));  \
+    initializeHandle(obj, raw_ptr);                                            \
+    return *obj;                                                               \
+  }                                                                            \
+  static object& ZoneHandleImpl(Zone* zone, Raw##object* raw_ptr) {            \
+    object* obj =                                                              \
+        reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone));        \
+    initializeHandle(obj, raw_ptr);                                            \
+    return *obj;                                                               \
+  }                                                                            \
   /* Initialize the handle based on the raw_ptr in the presence of null. */    \
   static void initializeHandle(object* obj, RawObject* raw_ptr) {              \
     if (raw_ptr != Object::null()) {                                           \
@@ -601,6 +610,29 @@
     *const_cast<FieldType*>(addr) = value;
   }
 
+  template <typename FieldType, typename ValueType, MemoryOrder order>
+  void StoreNonPointer(const FieldType* addr, ValueType value) const {
+    // Can't use Contains, as it uses tags_, which is set through this method.
+    ASSERT(reinterpret_cast<uword>(addr) >= RawObject::ToAddr(raw()));
+
+    if (order == MemoryOrder::kRelease) {
+      AtomicOperations::StoreRelease(const_cast<FieldType*>(addr), value);
+    } else {
+      ASSERT(order == MemoryOrder::kRelaxed);
+      StoreNonPointer<FieldType, ValueType>(addr, value);
+    }
+  }
+
+  template <typename FieldType, MemoryOrder order = MemoryOrder::kRelaxed>
+  FieldType LoadNonPointer(const FieldType* addr) const {
+    if (order == MemoryOrder::kAcquire) {
+      return AtomicOperations::LoadAcquire(const_cast<FieldType*>(addr));
+    } else {
+      ASSERT(order == MemoryOrder::kRelaxed);
+      return *const_cast<FieldType*>(addr);
+    }
+  }
+
   // Provides non-const access to non-pointer fields within the object. Such
   // access does not need a write barrier, but it is *not* GC-safe, since the
   // object might move, hence must be fully contained within a NoSafepointScope.
@@ -1322,7 +1354,7 @@
 
   // Allocate a class used for VM internal objects.
   template <class FakeObject>
-  static RawClass* New();
+  static RawClass* New(Isolate* isolate, bool register_class = true);
 
   // Allocate instance classes.
   static RawClass* New(const Library& lib,
@@ -1335,19 +1367,20 @@
                                     int num_fields);
 
   // Allocate the raw string classes.
-  static RawClass* NewStringClass(intptr_t class_id);
+  static RawClass* NewStringClass(intptr_t class_id, Isolate* isolate);
 
   // Allocate the raw TypedData classes.
-  static RawClass* NewTypedDataClass(intptr_t class_id);
+  static RawClass* NewTypedDataClass(intptr_t class_id, Isolate* isolate);
 
   // Allocate the raw TypedDataView/ByteDataView classes.
-  static RawClass* NewTypedDataViewClass(intptr_t class_id);
+  static RawClass* NewTypedDataViewClass(intptr_t class_id, Isolate* isolate);
 
   // Allocate the raw ExternalTypedData classes.
-  static RawClass* NewExternalTypedDataClass(intptr_t class_id);
+  static RawClass* NewExternalTypedDataClass(intptr_t class_id,
+                                             Isolate* isolate);
 
   // Allocate the raw Pointer classes.
-  static RawClass* NewPointerClass(intptr_t class_id);
+  static RawClass* NewPointerClass(intptr_t class_id, Isolate* isolate);
 
   // Register code that has used CHA for optimization.
   // TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
@@ -1502,7 +1535,9 @@
 
   // Allocate an instance class which has a VM implementation.
   template <class FakeInstance>
-  static RawClass* New(intptr_t id);
+  static RawClass* New(intptr_t id,
+                       Isolate* isolate,
+                       bool register_class = true);
 
   // Helper that calls 'Class::New<Instance>(kIllegalCid)'.
   static RawClass* NewInstanceClass();
@@ -1760,28 +1795,34 @@
 
   // Call site classification that is helpful for hot-reload. Call sites with
   // different `RebindRule` have to be rebound differently.
+#define FOR_EACH_REBIND_RULE(V)                                                \
+  V(Instance)                                                                  \
+  V(NoRebind)                                                                  \
+  V(NSMDispatch)                                                               \
+  V(Optimized)                                                                 \
+  V(Static)                                                                    \
+  V(Super)
+
   enum RebindRule {
-    kInstance,
-    kNoRebind,
-    kNSMDispatch,
-    kOptimized,
-    kStatic,
-    kSuper,
-    kNumRebindRules,
+#define REBIND_ENUM_DEF(name) k##name,
+    FOR_EACH_REBIND_RULE(REBIND_ENUM_DEF)
+#undef REBIND_ENUM_DEF
+        kNumRebindRules,
   };
+  static const char* RebindRuleToCString(RebindRule r);
+  static bool RebindRuleFromCString(const char* str, RebindRule* out);
   RebindRule rebind_rule() const;
   void set_rebind_rule(uint32_t rebind_rule) const;
 
-  // This bit is set when a call site becomes megamorphic and starts using a
-  // MegamorphicCache instead of ICData. It means that the entries in the
-  // ICData are incomplete and the MegamorphicCache needs to also be consulted
-  // to list the call site's observed receiver classes and targets.
-  bool is_megamorphic() const {
-    return MegamorphicBit::decode(raw_ptr()->state_bits_);
-  }
   void set_is_megamorphic(bool value) const {
-    StoreNonPointer(&raw_ptr()->state_bits_,
-                    MegamorphicBit::update(value, raw_ptr()->state_bits_));
+    // We don't have concurrent RW access to [state_bits_].
+    const uint32_t updated_bits =
+        MegamorphicBit::update(value, raw_ptr()->state_bits_);
+
+    // Though we ensure that once the state bits are updated, all other previous
+    // writes to the IC are visible as well.
+    StoreNonPointer<uint32_t, uint32_t, MemoryOrder::kRelease>(
+        &raw_ptr()->state_bits_, updated_bits);
   }
 
   // The length of the array. This includes all sentinel entries including
@@ -1915,8 +1956,6 @@
 
   RawUnlinkedCall* AsUnlinkedCall() const;
 
-  // Consider only used entries.
-  bool HasOneTarget() const;
   bool HasReceiverClassId(intptr_t class_id) const;
 
   // Note: passing non-null receiver_type enables exactness tracking for
@@ -1949,9 +1988,6 @@
 
   bool IsUsedAt(intptr_t i) const;
 
-  void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
-                             GrowableArray<intptr_t>* second) const;
-
   void PrintToJSONArray(const JSONArray& jsarray,
                         TokenPosition token_pos) const;
 
@@ -1995,6 +2031,20 @@
   void set_entries(const Array& value) const;
   void set_state_bits(uint32_t bits) const;
 
+  // This bit is set when a call site becomes megamorphic and starts using a
+  // MegamorphicCache instead of ICData. It means that the entries in the
+  // ICData are incomplete and the MegamorphicCache needs to also be consulted
+  // to list the call site's observed receiver classes and targets.
+  // In the compiler, this should only be read once by CallTargets to avoid the
+  // compiler seeing an unstable set of feedback.
+  bool is_megamorphic() const {
+    // Ensure any following load instructions do not get performed before this
+    // one.
+    const uint32_t bits = LoadNonPointer<uint32_t, MemoryOrder::kAcquire>(
+        &raw_ptr()->state_bits_);
+    return MegamorphicBit::decode(bits);
+  }
+
   bool ValidateInterceptor(const Function& target) const;
 
   enum {
@@ -2056,13 +2106,14 @@
   static RawArray* cached_icdata_arrays_[kCachedICDataArrayCount];
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object);
+  friend class CallSiteResetter;
+  friend class CallTargets;
   friend class Class;
+  friend class Deserializer;
   friend class ICDataTestTask;
   friend class Interpreter;
-  friend class SnapshotWriter;
   friend class Serializer;
-  friend class Deserializer;
-  friend class CallSiteResetter;
+  friend class SnapshotWriter;
 };
 
 // Often used constants for number of free function type parameters.
@@ -3961,12 +4012,6 @@
   void SetLoadInProgress() const;
   bool Loaded() const { return raw_ptr()->load_state_ == RawLibrary::kLoaded; }
   void SetLoaded() const;
-  bool LoadFailed() const {
-    return raw_ptr()->load_state_ == RawLibrary::kLoadError;
-  }
-  RawInstance* LoadError() const { return raw_ptr()->load_error_; }
-  void SetLoadError(const Instance& error) const;
-  RawInstance* TransitiveLoadError() const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawLibrary));
@@ -4240,6 +4285,7 @@
   static RawLibrary* ProfilerLibrary();
   static RawLibrary* TypedDataLibrary();
   static RawLibrary* VMServiceLibrary();
+  static RawLibrary* WasmLibrary();
 
   // Eagerly compile all classes and functions in the library.
   static RawError* CompileAll(bool ignore_error = false);
@@ -5363,6 +5409,9 @@
 
   void Disassemble(DisassemblyFormatter* formatter = NULL) const;
 
+  // Returns true if all BSS relocations in the code have been patched.
+  bool VerifyBSSRelocations() const;
+
   class Comments : public ZoneAllocated {
    public:
     static Comments& New(intptr_t count);
@@ -5758,7 +5807,6 @@
     return (source_positions_binary_offset() != 0);
   }
 
-#if !defined(PRODUCT)
   intptr_t local_variables_binary_offset() const {
     return raw_ptr()->local_variables_binary_offset_;
   }
@@ -5768,7 +5816,6 @@
   bool HasLocalVariablesInfo() const {
     return (local_variables_binary_offset() != 0);
   }
-#endif  // !defined(PRODUCT)
 
   RawLocalVarDescriptors* var_descriptors() const {
 #if defined(PRODUCT)
@@ -6460,27 +6507,12 @@
   intptr_t num_imports() const { return raw_ptr()->num_imports_; }
   RawLibrary* importer() const { return raw_ptr()->importer_; }
 
-  RawInstance* LoadError() const;
-
-  bool ContainsLibrary(const Library& library) const;
   RawLibrary* GetLibrary(int index) const;
   void AddImport(const Namespace& import) const;
   RawObject* LookupObject(const String& name) const;
   RawClass* LookupClass(const String& class_name) const;
 
   bool is_deferred_load() const { return raw_ptr()->is_deferred_load_; }
-  bool is_loaded() const { return raw_ptr()->is_loaded_; }
-  bool LoadLibrary() const;
-
-  // Return the list of code objects that were compiled when this
-  // prefix was not yet loaded. These code objects will be invalidated
-  // when the prefix is loaded.
-  RawArray* dependent_code() const;
-  void set_dependent_code(const Array& array) const;
-
-  // Add the given code object to the list of dependent ones.
-  void RegisterDependentCode(const Code& code) const;
-  void InvalidateDependentCode() const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawLibraryPrefix));
@@ -6499,7 +6531,6 @@
   void set_imports(const Array& value) const;
   void set_num_imports(intptr_t value) const;
   void set_importer(const Library& value) const;
-  void set_is_loaded() const;
 
   static RawLibraryPrefix* New();
 
@@ -6613,6 +6644,11 @@
   // Return true if this vector contains a recursive type argument.
   bool IsRecursive() const;
 
+  virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+                                            const char** error_str) const {
+    return Canonicalize();
+  }
+
   // Canonicalize only if instantiated, otherwise returns 'this'.
   RawTypeArguments* Canonicalize(TrailPtr trail = NULL) const;
 
@@ -7341,8 +7377,8 @@
   static intptr_t InstanceSize() { return 0; }
 
   static RawSmi* New(intptr_t value) {
-    RawSmi* raw_smi =
-        reinterpret_cast<RawSmi*>((value << kSmiTagShift) | kSmiTag);
+    RawSmi* raw_smi = reinterpret_cast<RawSmi*>(
+        (static_cast<uintptr_t>(value) << kSmiTagShift) | kSmiTag);
     ASSERT(ValueFromRawSmi(raw_smi) == value);
     return raw_smi;
   }
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 26b607b..432a6a0 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -671,7 +671,8 @@
       writer_->WriteUnsigned(kNullData);
     } else if (cid == kBoolCid) {
       writer_->WriteUnsigned(kBoolData);
-      writer_->WriteUnsigned(static_cast<RawBool*>(obj)->ptr()->value_);
+      writer_->WriteUnsigned(
+          static_cast<uintptr_t>(static_cast<RawBool*>(obj)->ptr()->value_));
     } else if (cid == kSmiCid) {
       UNREACHABLE();
     } else if (cid == kMintCid) {
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 3268d3b..6857b57 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -665,34 +665,17 @@
   }
 };
 
-class UnimplementedDeferredLibrary : public ReasonForCancelling {
- public:
-  UnimplementedDeferredLibrary(Zone* zone,
-                               const Library& from,
-                               const Library& to,
-                               const String& name)
-      : ReasonForCancelling(zone), from_(from), to_(to), name_(name) {}
-
- private:
-  const Library& from_;
-  const Library& to_;
-  const String& name_;
-
-  RawString* ToString() {
-    const String& lib_url = String::Handle(to_.url());
-    from_.ToCString();
-    return String::NewFormatted(
-        "Reloading support for deferred loading has not yet been implemented:"
-        " library '%s' has deferred import '%s'",
-        lib_url.ToCString(), name_.ToCString());
-  }
-};
-
 // This is executed before iterating over the instances.
 void Class::CheckReload(const Class& replacement,
                         IsolateReloadContext* context) const {
   ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
 
+  if (!is_declaration_loaded()) {
+    // The old class hasn't been used in any meanfully way, so the VM is okay
+    // with any change.
+    return;
+  }
+
   // Ensure is_enum_class etc have been set.
   replacement.EnsureDeclarationLoaded();
 
@@ -816,20 +799,7 @@
 
 void Library::CheckReload(const Library& replacement,
                           IsolateReloadContext* context) const {
-  // TODO(26878): If the replacement library uses deferred loading,
-  // reject it.  We do not yet support reloading deferred libraries.
-  LibraryPrefix& prefix = LibraryPrefix::Handle();
-  LibraryPrefixIterator it(replacement);
-  while (it.HasNext()) {
-    prefix = it.GetNext();
-    if (prefix.is_deferred_load()) {
-      const String& prefix_name = String::Handle(prefix.name());
-      context->AddReasonForCancelling(
-          new (context->zone()) UnimplementedDeferredLibrary(
-              context->zone(), *this, replacement, prefix_name));
-      return;
-    }
-  }
+  // Currently no library properties will prevent a reload.
 }
 
 void CallSiteResetter::Reset(const ICData& ic) {
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index c070103..1c12894 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -532,7 +532,7 @@
     DictionaryIterator entries(*this);
     Object& entry = Object::Handle();
     LibraryPrefix& prefix = LibraryPrefix::Handle();
-    String& prefixName = String::Handle();
+    String& prefix_name = String::Handle();
     while (entries.HasNext()) {
       entry = entries.GetNext();
       if (entry.IsLibraryPrefix()) {
@@ -547,15 +547,62 @@
             jsdep.AddProperty("isDeferred", prefix.is_deferred_load());
             jsdep.AddProperty("isExport", false);
             jsdep.AddProperty("isImport", true);
-            prefixName = prefix.name();
-            ASSERT(!prefixName.IsNull());
-            jsdep.AddProperty("prefix", prefixName.ToCString());
+            prefix_name = prefix.name();
+            ASSERT(!prefix_name.IsNull());
+            jsdep.AddProperty("prefix", prefix_name.ToCString());
             target = ns.library();
             jsdep.AddProperty("target", target);
           }
         }
       }
     }
+
+    if (is_declared_in_bytecode()) {
+      // Make sure top level class (containing annotations) is fully loaded.
+      EnsureTopLevelClassIsFinalized();
+      Array& metadata = Array::Handle(GetExtendedMetadata(*this, 1));
+      if (metadata.Length() != 0) {
+        // Library has the only element in the extended metadata.
+        metadata ^= metadata.At(0);
+        if (!metadata.IsNull()) {
+          Thread* thread = Thread::Current();
+          auto& desc = Array::Handle();
+          auto& target_uri = String::Handle();
+          auto& is_export = Bool::Handle();
+          auto& is_deferred = Bool::Handle();
+          for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
+            desc ^= metadata.At(i);
+            // Each dependency is represented as an array with the following
+            // layout:
+            //  [0] = target library URI (String)
+            //  [1] = is_export (bool)
+            //  [2] = is_deferred (bool)
+            //  [3] = prefix (String or null)
+            //  ...
+            // The library dependencies are encoded by getLibraryAnnotations(),
+            // pkg/vm/lib/bytecode/gen_bytecode.dart.
+            target_uri ^= desc.At(0);
+            is_export ^= desc.At(1);
+            is_deferred ^= desc.At(2);
+            prefix_name ^= desc.At(3);
+
+            target = Library::LookupLibrary(thread, target_uri);
+            if (target.IsNull()) {
+              continue;
+            }
+
+            JSONObject jsdep(&jsarr);
+            jsdep.AddProperty("isDeferred", is_deferred.value());
+            jsdep.AddProperty("isExport", is_export.value());
+            jsdep.AddProperty("isImport", !is_export.value());
+            if (!prefix_name.IsNull()) {
+              jsdep.AddProperty("prefix", prefix_name.ToCString());
+            }
+            jsdep.AddProperty("target", target);
+          }
+        }
+      }
+    }
   }
   {
     JSONArray jsarr(&jsobj, "variables");
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 0237cc0..6dcf00a 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -80,8 +80,6 @@
   ASSERT(this->out_of_memory() == Instance::null());
   ASSERT(this->preallocated_stack_trace() == StackTrace::null());
 
-  this->pending_deferred_loads_ = GrowableObjectArray::New();
-
   this->closure_functions_ = GrowableObjectArray::New();
   this->resume_capabilities_ = GrowableObjectArray::New();
   this->exit_listeners_ = GrowableObjectArray::New();
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index f0ded97..77461f0 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -29,7 +29,8 @@
   M(Mirrors, mirrors)                                                          \
   M(Profiler, profiler)                                                        \
   M(TypedData, typed_data)                                                     \
-  M(VMService, _vmservice)
+  M(VMService, _vmservice)                                                     \
+  M(Wasm, wasm)
 
 #define OBJECT_STORE_FIELD_LIST(R_, RW)                                        \
   RW(Class, object_class)                                                      \
@@ -101,12 +102,11 @@
   RW(Library, root_library)                                                    \
   RW(Library, typed_data_library)                                              \
   RW(Library, _vmservice_library)                                              \
+  RW(Library, wasm_library)                                                    \
   RW(GrowableObjectArray, libraries)                                           \
   RW(Array, libraries_map)                                                     \
   RW(GrowableObjectArray, closure_functions)                                   \
   RW(GrowableObjectArray, pending_classes)                                     \
-  RW(GrowableObjectArray, pending_unevaluated_const_fields)                    \
-  R_(GrowableObjectArray, pending_deferred_loads)                              \
   R_(GrowableObjectArray, resume_capabilities)                                 \
   R_(GrowableObjectArray, exit_listeners)                                      \
   R_(GrowableObjectArray, error_listeners)                                     \
@@ -126,7 +126,6 @@
   RW(Function, complete_on_async_return)                                       \
   RW(Class, async_star_stream_controller)                                      \
   RW(ObjectPool, global_object_pool)                                           \
-  RW(Array, library_load_error_table)                                          \
   RW(Array, unique_dynamic_targets)                                            \
   RW(GrowableObjectArray, megamorphic_cache_table)                             \
   RW(Code, build_method_extractor_code)                                        \
@@ -199,10 +198,6 @@
     }
   }
 
-  void clear_pending_deferred_loads() {
-    pending_deferred_loads_ = GrowableObjectArray::New();
-  }
-
   void SetMegamorphicMissHandler(const Code& code, const Function& func) {
     // Hold onto the code so it is traced and not detached from the function.
     megamorphic_miss_code_ = code.raw();
@@ -242,7 +237,7 @@
   RawObject** to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
       case Snapshot::kFull:
-        return reinterpret_cast<RawObject**>(&library_load_error_table_);
+        return reinterpret_cast<RawObject**>(&global_object_pool_);
       case Snapshot::kFullJIT:
       case Snapshot::kFullAOT:
         return reinterpret_cast<RawObject**>(&megamorphic_miss_function_);
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index eecf7fd..9baba7e 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -599,7 +599,7 @@
   va_end(measure_args);
 
   char* buffer;
-  if (zone) {
+  if (zone != nullptr) {
     buffer = zone->Alloc<char>(len + 1);
   } else {
     buffer = reinterpret_cast<char*>(malloc(len + 1));
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 6abaac0..ae99c87 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9,6 +9,7 @@
 
 #include "lib/invocation_mirror.h"
 #include "platform/utils.h"
+#include "vm/bit_vector.h"
 #include "vm/bootstrap.h"
 #include "vm/class_finalizer.h"
 #include "vm/compiler/aot/precompiler.h"
@@ -58,7 +59,6 @@
       expression_temp_var_(NULL),
       entry_points_temp_var_(NULL),
       finally_return_temp_var_(NULL),
-      deferred_prefixes_(new ZoneGrowableArray<const LibraryPrefix*>()),
       guarded_fields_(new ZoneGrowableArray<const Field*>()),
       default_parameter_values_(NULL),
       raw_type_arguments_var_(NULL),
@@ -184,20 +184,6 @@
   regexp_compile_data_ = regexp_compile_data;
 }
 
-void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
-  // 'deferred_prefixes_' are used to invalidate code, but no invalidation is
-  // needed if --load_deferred_eagerly.
-  ASSERT(!FLAG_load_deferred_eagerly);
-  ASSERT(prefix.is_deferred_load());
-  ASSERT(!prefix.is_loaded());
-  for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
-    if ((*deferred_prefixes_)[i]->raw() == prefix.raw()) {
-      return;
-    }
-  }
-  deferred_prefixes_->Add(&LibraryPrefix::ZoneHandle(Z, prefix.raw()));
-}
-
 void ParsedFunction::AllocateVariables() {
   ASSERT(!function().IsIrregexpFunction());
   LocalScope* scope = this->scope();
@@ -316,6 +302,33 @@
   num_stack_locals_ = num_stack_locals;
 }
 
+void ParsedFunction::SetCovariantParameters(
+    const BitVector* covariant_parameters) {
+  ASSERT(covariant_parameters_ == nullptr);
+  ASSERT(covariant_parameters->length() == function_.NumParameters());
+  covariant_parameters_ = covariant_parameters;
+}
+
+void ParsedFunction::SetGenericCovariantImplParameters(
+    const BitVector* generic_covariant_impl_parameters) {
+  ASSERT(generic_covariant_impl_parameters_ == nullptr);
+  ASSERT(generic_covariant_impl_parameters->length() ==
+         function_.NumParameters());
+  generic_covariant_impl_parameters_ = generic_covariant_impl_parameters;
+}
+
+bool ParsedFunction::IsCovariantParameter(intptr_t i) const {
+  ASSERT(covariant_parameters_ != nullptr);
+  ASSERT((i >= 0) && (i < function_.NumParameters()));
+  return covariant_parameters_->Contains(i);
+}
+
+bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const {
+  ASSERT(generic_covariant_impl_parameters_ != nullptr);
+  ASSERT((i >= 0) && (i < function_.NumParameters()));
+  return generic_covariant_impl_parameters_->Contains(i);
+}
+
 }  // namespace dart
 
 #endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 2328080..f574ea6 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -30,6 +30,7 @@
 }  // namespace kernel
 
 class ArgumentsDescriptor;
+class BitVector;
 class Isolate;
 class LocalScope;
 class LocalVariable;
@@ -155,12 +156,6 @@
   LocalVariable* EnsureExpressionTemp();
   LocalVariable* EnsureEntryPointsTemp();
 
-  bool HasDeferredPrefixes() const { return deferred_prefixes_->length() != 0; }
-  ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
-    return deferred_prefixes_;
-  }
-  void AddDeferredPrefix(const LibraryPrefix& prefix);
-
   ZoneGrowableArray<const Field*>* guarded_fields() const {
     return guarded_fields_;
   }
@@ -226,6 +221,28 @@
     return default_function_type_arguments_;
   }
 
+  // Remembers the set of covariant parameters.
+  // [covariant_parameters] is a bitvector of function.NumParameters() length.
+  void SetCovariantParameters(const BitVector* covariant_parameters);
+
+  // Remembers the set of generic-covariant-impl parameters.
+  // [covariant_parameters] is a bitvector of function.NumParameters() length.
+  void SetGenericCovariantImplParameters(
+      const BitVector* generic_covariant_impl_parameters);
+
+  bool HasCovariantParametersInfo() const {
+    return covariant_parameters_ != nullptr;
+  }
+
+  // Returns true if i-th parameter is covariant.
+  // SetCovariantParameters should be called before using this method.
+  bool IsCovariantParameter(intptr_t i) const;
+
+  // Returns true if i-th parameter is generic-covariant-impl.
+  // SetGenericCovariantImplParameters should be called before using this
+  // method.
+  bool IsGenericCovariantImplParameter(intptr_t i) const;
+
  private:
   Thread* thread_;
   const Function& function_;
@@ -240,7 +257,6 @@
   LocalVariable* expression_temp_var_;
   LocalVariable* entry_points_temp_var_;
   LocalVariable* finally_return_temp_var_;
-  ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
   ZoneGrowableArray<const Field*>* guarded_fields_;
   ZoneGrowableArray<const Instance*>* default_parameter_values_;
 
@@ -256,6 +272,9 @@
 
   TypeArguments& default_function_type_arguments_;
 
+  const BitVector* covariant_parameters_ = nullptr;
+  const BitVector* generic_covariant_impl_parameters_ = nullptr;
+
   friend class Parser;
   DISALLOW_COPY_AND_ASSIGN(ParsedFunction);
 };
diff --git a/runtime/vm/pointer_tagging.h b/runtime/vm/pointer_tagging.h
index a4d6d9f..e4a59e6 100644
--- a/runtime/vm/pointer_tagging.h
+++ b/runtime/vm/pointer_tagging.h
@@ -5,6 +5,9 @@
 #ifndef RUNTIME_VM_POINTER_TAGGING_H_
 #define RUNTIME_VM_POINTER_TAGGING_H_
 
+#include "platform/assert.h"
+#include "platform/globals.h"
+
 // This header defines constants associated with pointer tagging:
 //
 //    * which bits determine whether or not this is a Smi value or a heap
diff --git a/runtime/vm/proccpuinfo.cc b/runtime/vm/proccpuinfo.cc
index 3dfb2cb..6278627 100644
--- a/runtime/vm/proccpuinfo.cc
+++ b/runtime/vm/proccpuinfo.cc
@@ -76,7 +76,7 @@
 
   // Skip to the first colon followed by a space.
   p = strchr(p + fieldlen, ':');
-  if (p == NULL || !isspace(p[1])) {
+  if (p == NULL || (isspace(p[1]) == 0)) {
     return NULL;
   }
   p += 2;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 52cbcf5..fee9e8e 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1063,6 +1063,9 @@
   // purposes as some samples may be collected when no thread exists.
   if (thread != NULL) {
     sample->set_thread_task(thread->task_kind());
+    sample->set_vm_tag(thread->vm_tag());
+  } else {
+    sample->set_vm_tag(VMTag::kEmbedderTagId);
   }
   return sample;
 }
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index f0280fc..9c879ae 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -477,24 +477,56 @@
   const char* Name() const {
     if (code_.IsCode()) {
       return Code::Cast(code_).Name();
-    } else {
+    } else if (code_.IsBytecode()) {
       return Bytecode::Cast(code_).Name();
+    } else {
+      return "";
     }
   }
 
   const char* QualifiedName() const {
     if (code_.IsCode()) {
       return Code::Cast(code_).QualifiedName();
-    } else {
+    } else if (code_.IsBytecode()) {
       return Bytecode::Cast(code_).QualifiedName();
+    } else {
+      return "";
+    }
+  }
+
+  bool IsStubCode() const {
+    if (code_.IsCode()) {
+      return Code::Cast(code_).IsStubCode();
+    } else if (code_.IsBytecode()) {
+      return (Bytecode::Cast(code_).function() == Function::null());
+    } else {
+      return false;
+    }
+  }
+
+  bool IsAllocationStubCode() const {
+    if (code_.IsCode()) {
+      return Code::Cast(code_).IsAllocationStubCode();
+    } else {
+      return false;
+    }
+  }
+
+  bool IsTypeTestStubCode() const {
+    if (code_.IsCode()) {
+      return Code::Cast(code_).IsTypeTestStubCode();
+    } else {
+      return false;
     }
   }
 
   RawObject* owner() const {
     if (code_.IsCode()) {
       return Code::Cast(code_).owner();
-    } else {
+    } else if (code_.IsBytecode()) {
       return Bytecode::Cast(code_).function();
+    } else {
+      return Object::null();
     }
   }
 
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index d3a1450..db033d0 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -225,16 +225,18 @@
 }
 
 void ProfileFunction::PrintToJSONObject(JSONObject* func) {
-  func->AddProperty("type", "@Function");
+  func->AddProperty("type", "NativeFunction");
   func->AddProperty("name", name());
   func->AddProperty("_kind", KindToCString(kind()));
 }
 
 void ProfileFunction::PrintToJSONArray(JSONArray* functions) {
   JSONObject obj(functions);
+  obj.AddProperty("type", "ProfileFunction");
   obj.AddProperty("kind", KindToCString(kind()));
   obj.AddProperty("inclusiveTicks", inclusive_ticks());
   obj.AddProperty("exclusiveTicks", exclusive_ticks());
+  obj.AddProperty("resolvedUrl", ResolvedScriptUrl());
   if (kind() == kDartFunction) {
     ASSERT(!function_.IsNull());
     obj.AddProperty("function", function_);
@@ -243,7 +245,7 @@
     PrintToJSONObject(&func);
   }
   {
-    JSONArray codes(&obj, "codes");
+    JSONArray codes(&obj, "_codes");
     for (intptr_t i = 0; i < profile_codes_.length(); i++) {
       intptr_t code_index = profile_codes_[i];
       codes.AddValue(code_index);
@@ -865,335 +867,107 @@
   }
 }
 
-ProfileTrieNode::ProfileTrieNode(intptr_t table_index)
-    : table_index_(table_index),
-      count_(0),
-      exclusive_allocations_(0),
-      inclusive_allocations_(0),
-      children_(0),
-      parent_(NULL),
-      frame_id_(-1) {
-  ASSERT(table_index_ >= 0);
+void ProfileCodeInlinedFunctionsCache::Get(
+    uword pc,
+    const Code& code,
+    ProcessedSample* sample,
+    intptr_t frame_index,
+    // Outputs:
+    GrowableArray<const Function*>** inlined_functions,
+    GrowableArray<TokenPosition>** inlined_token_positions,
+    TokenPosition* token_position) {
+  const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+  if (FindInCache(pc, offset, inlined_functions, inlined_token_positions,
+                  token_position)) {
+    // Found in cache.
+    return;
+  }
+  Add(pc, code, sample, frame_index, inlined_functions, inlined_token_positions,
+      token_position);
 }
 
-ProfileTrieNode::~ProfileTrieNode() {}
-
-void ProfileTrieNode::Tick(ProcessedSample* sample, bool exclusive) {
-  count_++;
-  IncrementAllocation(sample->native_allocation_size_bytes(), exclusive);
+bool ProfileCodeInlinedFunctionsCache::FindInCache(
+    uword pc,
+    intptr_t offset,
+    GrowableArray<const Function*>** inlined_functions,
+    GrowableArray<TokenPosition>** inlined_token_positions,
+    TokenPosition* token_position) {
+  // Simple linear scan.
+  for (intptr_t i = 0; i < kCacheSize; i++) {
+    intptr_t index = (last_hit_ + i) % kCacheSize;
+    if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
+      // Hit.
+      if (cache_[index].inlined_functions.length() == 0) {
+        *inlined_functions = NULL;
+        *inlined_token_positions = NULL;
+      } else {
+        *inlined_functions = &cache_[index].inlined_functions;
+        *inlined_token_positions = &cache_[index].inlined_token_positions;
+      }
+      *token_position = cache_[index].token_position;
+      cache_hit_++;
+      last_hit_ = index;
+      return true;
+    }
+  }
+  cache_miss_++;
+  return false;
 }
 
-void ProfileTrieNode::SortChildren() {
-  children_.Sort(ProfileTrieNodeCompare);
-  // Recurse.
-  for (intptr_t i = 0; i < children_.length(); i++) {
-    children_[i]->SortChildren();
+// Add to cache and fill in outputs.
+void ProfileCodeInlinedFunctionsCache::Add(
+    uword pc,
+    const Code& code,
+    ProcessedSample* sample,
+    intptr_t frame_index,
+    // Outputs:
+    GrowableArray<const Function*>** inlined_functions,
+    GrowableArray<TokenPosition>** inlined_token_positions,
+    TokenPosition* token_position) {
+  const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+  CacheEntry* cache_entry = &cache_[NextFreeIndex()];
+  cache_entry->Reset();
+  cache_entry->pc = pc;
+  cache_entry->offset = offset;
+  code.GetInlinedFunctionsAtInstruction(
+      offset, &(cache_entry->inlined_functions),
+      &(cache_entry->inlined_token_positions));
+  if (cache_entry->inlined_functions.length() == 0) {
+    *inlined_functions = NULL;
+    *inlined_token_positions = NULL;
+    *token_position = cache_entry->token_position = TokenPosition();
+    return;
   }
+
+  // Write outputs.
+  *inlined_functions = &(cache_entry->inlined_functions);
+  *inlined_token_positions = &(cache_entry->inlined_token_positions);
+  *token_position = cache_entry->token_position =
+      cache_entry->inlined_token_positions[0];
 }
 
-intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) {
-  for (intptr_t i = 0; i < children_.length(); i++) {
-    if (children_[i] == node) {
-      return i;
-    }
+intptr_t ProfileCodeInlinedFunctionsCache::OffsetForPC(uword pc,
+                                                       const Code& code,
+                                                       ProcessedSample* sample,
+                                                       intptr_t frame_index) {
+  intptr_t offset = pc - code.PayloadStart();
+  if (frame_index != 0) {
+    // The PC of frames below the top frame is a call's return address,
+    // which can belong to a different inlining interval than the call.
+    offset--;
+  } else if (sample->IsAllocationSample()) {
+    // Allocation samples skip the top frame, so the top frame's pc is
+    // also a call's return address.
+    offset--;
+  } else if (!sample->first_frame_executing()) {
+    // If the first frame wasn't executing code (i.e. we started to collect
+    // the stack trace at an exit frame), the top frame's pc is also a
+    // call's return address.
+    offset--;
   }
-  return -1;
+  return offset;
 }
 
-class ProfileCodeTrieNode : public ProfileTrieNode {
- public:
-  explicit ProfileCodeTrieNode(intptr_t table_index)
-      : ProfileTrieNode(table_index) {}
-
-  void PrintToJSONArray(JSONArray* array) const {
-    ASSERT(array != NULL);
-    // Write CodeRegion index.
-    array->AddValue(table_index());
-    // Write count.
-    array->AddValue(count());
-    // Write number of children.
-    intptr_t child_count = NumChildren();
-    array->AddValue(child_count);
-    // Write inclusive allocations.
-    array->AddValue64(inclusive_allocations_);
-    // Write exclusive allocations.
-    array->AddValue64(exclusive_allocations_);
-    // Recurse.
-    for (intptr_t i = 0; i < child_count; i++) {
-      children_[i]->PrintToJSONArray(array);
-    }
-  }
-
-  const char* ToCString(Profile* profile) const {
-    return profile->GetCode(table_index())->name();
-  }
-
-  ProfileCodeTrieNode* GetChild(intptr_t child_table_index) {
-    const intptr_t length = NumChildren();
-    intptr_t i = 0;
-    while (i < length) {
-      ProfileCodeTrieNode* child =
-          reinterpret_cast<ProfileCodeTrieNode*>(children_[i]);
-      if (child->table_index() == child_table_index) {
-        return child;
-      }
-      if (child->table_index() > child_table_index) {
-        break;
-      }
-      i++;
-    }
-    ProfileCodeTrieNode* child = new ProfileCodeTrieNode(child_table_index);
-    if (i < length) {
-      // Insert at i.
-      children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
-    } else {
-      // Add to end.
-      children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
-    }
-    return child;
-  }
-};
-
-class ProfileFunctionTrieNodeCode {
- public:
-  explicit ProfileFunctionTrieNodeCode(intptr_t index)
-      : code_index_(index), ticks_(0) {}
-
-  intptr_t index() const { return code_index_; }
-
-  void Tick() { ticks_++; }
-
-  intptr_t ticks() const { return ticks_; }
-
- private:
-  intptr_t code_index_;
-  intptr_t ticks_;
-};
-
-class ProfileFunctionTrieNode : public ProfileTrieNode {
- public:
-  explicit ProfileFunctionTrieNode(intptr_t table_index)
-      : ProfileTrieNode(table_index), code_objects_(1) {}
-
-  void PrintToJSONArray(JSONArray* array) const {
-    ASSERT(array != NULL);
-    // Write CodeRegion index.
-    array->AddValue(table_index());
-    // Write count.
-    array->AddValue(count());
-    // Write inclusive allocations.
-    array->AddValue64(inclusive_allocations_);
-    // Write exclusive allocations.
-    array->AddValue64(exclusive_allocations_);
-    // Write number of code objects.
-    intptr_t code_count = code_objects_.length();
-    array->AddValue(code_count);
-    // Write each code object index and ticks.
-    for (intptr_t i = 0; i < code_count; i++) {
-      array->AddValue(code_objects_[i].index());
-      array->AddValue(code_objects_[i].ticks());
-    }
-    // Write number of children.
-    intptr_t child_count = children_.length();
-    array->AddValue(child_count);
-    // Recurse.
-    for (intptr_t i = 0; i < child_count; i++) {
-      children_[i]->PrintToJSONArray(array);
-    }
-  }
-
-  const char* ToCString(Profile* profile) const {
-    ProfileFunction* f = profile->GetFunction(table_index());
-    return f->Name();
-  }
-
-  ProfileFunctionTrieNode* GetChild(intptr_t child_table_index) {
-    const intptr_t length = NumChildren();
-    intptr_t i = 0;
-    while (i < length) {
-      ProfileFunctionTrieNode* child =
-          reinterpret_cast<ProfileFunctionTrieNode*>(children_[i]);
-      if (child->table_index() == child_table_index) {
-        return child;
-      }
-      if (child->table_index() > child_table_index) {
-        break;
-      }
-      i++;
-    }
-    ProfileFunctionTrieNode* child =
-        new ProfileFunctionTrieNode(child_table_index);
-    if (i < length) {
-      // Insert at i.
-      children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
-    } else {
-      // Add to end.
-      children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
-    }
-    return child;
-  }
-
-  void AddCodeObjectIndex(intptr_t index) {
-    for (intptr_t i = 0; i < code_objects_.length(); i++) {
-      ProfileFunctionTrieNodeCode& code_object = code_objects_[i];
-      if (code_object.index() == index) {
-        code_object.Tick();
-        return;
-      }
-    }
-    ProfileFunctionTrieNodeCode code_object(index);
-    code_object.Tick();
-    code_objects_.Add(code_object);
-  }
-
- private:
-  ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_;
-};
-
-class ProfileCodeInlinedFunctionsCache : public ValueObject {
- public:
-  ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) {
-    for (intptr_t i = 0; i < kCacheSize; i++) {
-      cache_[i].Reset();
-    }
-    cache_hit_ = 0;
-    cache_miss_ = 0;
-  }
-
-  ~ProfileCodeInlinedFunctionsCache() {
-    if (FLAG_trace_profiler) {
-      intptr_t total = cache_hit_ + cache_miss_;
-      OS::PrintErr("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total,
-                   cache_hit_, cache_miss_);
-    }
-  }
-
-  void Get(uword pc,
-           const Code& code,
-           ProcessedSample* sample,
-           intptr_t frame_index,
-           // Outputs:
-           GrowableArray<const Function*>** inlined_functions,
-           GrowableArray<TokenPosition>** inlined_token_positions,
-           TokenPosition* token_position) {
-    const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
-    if (FindInCache(pc, offset, inlined_functions, inlined_token_positions,
-                    token_position)) {
-      // Found in cache.
-      return;
-    }
-    Add(pc, code, sample, frame_index, inlined_functions,
-        inlined_token_positions, token_position);
-  }
-
- private:
-  bool FindInCache(uword pc,
-                   intptr_t offset,
-                   GrowableArray<const Function*>** inlined_functions,
-                   GrowableArray<TokenPosition>** inlined_token_positions,
-                   TokenPosition* token_position) {
-    // Simple linear scan.
-    for (intptr_t i = 0; i < kCacheSize; i++) {
-      intptr_t index = (last_hit_ + i) % kCacheSize;
-      if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
-        // Hit.
-        if (cache_[index].inlined_functions.length() == 0) {
-          *inlined_functions = NULL;
-          *inlined_token_positions = NULL;
-        } else {
-          *inlined_functions = &cache_[index].inlined_functions;
-          *inlined_token_positions = &cache_[index].inlined_token_positions;
-        }
-        *token_position = cache_[index].token_position;
-        cache_hit_++;
-        last_hit_ = index;
-        return true;
-      }
-    }
-    cache_miss_++;
-    return false;
-  }
-
-  // Add to cache and fill in outputs.
-  void Add(uword pc,
-           const Code& code,
-           ProcessedSample* sample,
-           intptr_t frame_index,
-           // Outputs:
-           GrowableArray<const Function*>** inlined_functions,
-           GrowableArray<TokenPosition>** inlined_token_positions,
-           TokenPosition* token_position) {
-    const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
-    CacheEntry* cache_entry = &cache_[NextFreeIndex()];
-    cache_entry->Reset();
-    cache_entry->pc = pc;
-    cache_entry->offset = offset;
-    code.GetInlinedFunctionsAtInstruction(
-        offset, &(cache_entry->inlined_functions),
-        &(cache_entry->inlined_token_positions));
-    if (cache_entry->inlined_functions.length() == 0) {
-      *inlined_functions = NULL;
-      *inlined_token_positions = NULL;
-      *token_position = cache_entry->token_position = TokenPosition();
-      return;
-    }
-
-    // Write outputs.
-    *inlined_functions = &(cache_entry->inlined_functions);
-    *inlined_token_positions = &(cache_entry->inlined_token_positions);
-    *token_position = cache_entry->token_position =
-        cache_entry->inlined_token_positions[0];
-  }
-
-  intptr_t NextFreeIndex() {
-    cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
-    return cache_cursor_;
-  }
-
-  intptr_t OffsetForPC(uword pc,
-                       const Code& code,
-                       ProcessedSample* sample,
-                       intptr_t frame_index) {
-    intptr_t offset = pc - code.PayloadStart();
-    if (frame_index != 0) {
-      // The PC of frames below the top frame is a call's return address,
-      // which can belong to a different inlining interval than the call.
-      offset--;
-    } else if (sample->IsAllocationSample()) {
-      // Allocation samples skip the top frame, so the top frame's pc is
-      // also a call's return address.
-      offset--;
-    } else if (!sample->first_frame_executing()) {
-      // If the first frame wasn't executing code (i.e. we started to collect
-      // the stack trace at an exit frame), the top frame's pc is also a
-      // call's return address.
-      offset--;
-    }
-    return offset;
-  }
-
-  struct CacheEntry {
-    void Reset() {
-      pc = 0;
-      offset = 0;
-      inlined_functions.Clear();
-      inlined_token_positions.Clear();
-    }
-    uword pc;
-    intptr_t offset;
-    GrowableArray<const Function*> inlined_functions;
-    GrowableArray<TokenPosition> inlined_token_positions;
-    TokenPosition token_position;
-  };
-
-  static const intptr_t kCacheSize = 128;
-  intptr_t cache_cursor_;
-  intptr_t last_hit_;
-  CacheEntry cache_[kCacheSize];
-  intptr_t cache_miss_;
-  intptr_t cache_hit_;
-};
-
 class ProfileBuilder : public ValueObject {
  public:
   enum ProfileInfoKind {
@@ -1209,20 +983,15 @@
   ProfileBuilder(Thread* thread,
                  SampleFilter* filter,
                  SampleBuffer* sample_buffer,
-                 Profile::TagOrder tag_order,
-                 intptr_t extra_tags,
                  Profile* profile)
       : thread_(thread),
         vm_isolate_(Dart::vm_isolate()),
         filter_(filter),
         sample_buffer_(sample_buffer),
-        tag_order_(tag_order),
-        extra_tags_(extra_tags),
         profile_(profile),
         deoptimized_code_(new DeoptimizedCodeSet(thread->isolate())),
         null_code_(Code::null()),
         null_function_(Function::ZoneHandle()),
-        tick_functions_(false),
         inclusive_tree_(false),
         samples_(NULL),
         info_kind_(kNone) {
@@ -1241,12 +1010,7 @@
     BuildCodeTable();
     FinalizeCodeIndexes();
     BuildFunctionTable();
-
-    BuildCodeTrie(Profile::kExclusiveCode);
-    BuildCodeTrie(Profile::kInclusiveCode);
-
-    BuildFunctionTrie(Profile::kExclusiveFunction);
-    BuildFunctionTrie(Profile::kInclusiveFunction);
+    PopulateFunctionTicks();
   }
 
  private:
@@ -1256,11 +1020,6 @@
            (sample->first_frame_executing() || sample->IsAllocationSample());
   }
 
-  static bool IsInclusiveTrie(Profile::TrieKind kind) {
-    return (kind == Profile::kInclusiveFunction) ||
-           (kind == Profile::kInclusiveCode);
-  }
-
   void Setup() {
     profile_->live_code_ = new ProfileCodeTable();
     profile_->dead_code_ = new ProfileCodeTable();
@@ -1413,202 +1172,27 @@
     }
   }
 
-  void BuildCodeTrie(Profile::TrieKind kind) {
-    ProfileCodeTrieNode* root =
-        new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId));
-    inclusive_tree_ = IsInclusiveTrie(kind);
-    if (inclusive_tree_) {
-      BuildInclusiveCodeTrie(root);
-    } else {
-      BuildExclusiveCodeTrie(root);
-    }
-    root->SortChildren();
-    profile_->roots_[static_cast<intptr_t>(kind)] = root;
-  }
-
-  void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) {
-    ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie",
-                  FLAG_trace_profiler);
+  void PopulateFunctionTicks() {
+    ScopeTimer sw("ProfileBuilder::PopulateFunctionTicks", FLAG_trace_profiler);
     for (intptr_t sample_index = 0; sample_index < samples_->length();
          sample_index++) {
       ProcessedSample* sample = samples_->At(sample_index);
 
-      // Tick the root.
-      ProfileCodeTrieNode* current = root;
-      current->Tick(sample);
-
-      // VM & User tags.
-      current =
-          AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
-      ResetKind();
-
-      // Truncated tag.
-      if (sample->truncated()) {
-        current = AppendTruncatedTag(current, sample);
-      }
-
-      // Walk the sampled PCs.
-      for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
-           frame_index--) {
-        ASSERT(sample->At(frame_index) != 0);
-        intptr_t index =
-            GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
-        ASSERT(index >= 0);
-        ProfileCode* profile_code =
-            GetProfileCode(sample->At(frame_index), sample->timestamp());
-        ASSERT(profile_code->code_table_index() == index);
-        const AbstractCode code = profile_code->code();
-        current = AppendKind(code, current, sample);
-        current = current->GetChild(index);
-        current->Tick(sample, (frame_index == 0));
-      }
-
-      if (!sample->first_frame_executing()) {
-        current = AppendExitFrame(sample->vm_tag(), current, sample);
-      }
-
-      sample->set_timeline_code_trie(current);
-    }
-  }
-
-  void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) {
-    ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie",
-                  FLAG_trace_profiler);
-    for (intptr_t sample_index = 0; sample_index < samples_->length();
-         sample_index++) {
-      ProcessedSample* sample = samples_->At(sample_index);
-
-      // Tick the root.
-      ProfileCodeTrieNode* current = root;
-      current->Tick(sample);
-      // VM & User tags.
-      current =
-          AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
-      ResetKind();
-
-      if (!sample->first_frame_executing()) {
-        current = AppendExitFrame(sample->vm_tag(), current, sample);
-      }
-
       // Walk the sampled PCs.
       for (intptr_t frame_index = 0; frame_index < sample->length();
            frame_index++) {
         ASSERT(sample->At(frame_index) != 0);
-        intptr_t index =
-            GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
-        ASSERT(index >= 0);
-        ProfileCode* profile_code =
-            GetProfileCode(sample->At(frame_index), sample->timestamp());
-        ASSERT(profile_code->code_table_index() == index);
-        const AbstractCode code = profile_code->code();
-        current = current->GetChild(index);
-        if (ShouldTickNode(sample, frame_index)) {
-          current->Tick(sample, (frame_index == 0));
-        }
-        current = AppendKind(code, current, sample);
+        ProcessFrame(sample_index, sample, frame_index);
       }
-      // Truncated tag.
       if (sample->truncated()) {
-        current = AppendTruncatedTag(current, sample);
-      }
-    }
-  }
-
-  void BuildFunctionTrie(Profile::TrieKind kind) {
-    ProfileFunctionTrieNode* root = new ProfileFunctionTrieNode(
-        GetProfileFunctionTagIndex(VMTag::kRootTagId));
-    // We tick the functions while building the trie, but, we don't want to do
-    // it for both tries, just the exclusive trie.
-    inclusive_tree_ = IsInclusiveTrie(kind);
-    tick_functions_ = !inclusive_tree_;
-    if (inclusive_tree_) {
-      BuildInclusiveFunctionTrie(root);
-    } else {
-      BuildExclusiveFunctionTrie(root);
-    }
-    root->SortChildren();
-    profile_->roots_[static_cast<intptr_t>(kind)] = root;
-  }
-
-  void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
-    ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie",
-                  FLAG_trace_profiler);
-    ASSERT(!tick_functions_);
-    for (intptr_t sample_index = 0; sample_index < samples_->length();
-         sample_index++) {
-      ProcessedSample* sample = samples_->At(sample_index);
-
-      // Tick the root.
-      ProfileFunctionTrieNode* current = root;
-      current->Tick(sample);
-      // VM & User tags.
-      current =
-          AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
-      // Truncated tag.
-      if (sample->truncated()) {
-        current = AppendTruncatedTag(current, sample);
-      }
-
-      // Walk the sampled PCs.
-      for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
-           frame_index--) {
-        ASSERT(sample->At(frame_index) != 0);
-        current = ProcessFrame(current, sample_index, sample, frame_index);
-      }
-
-      if (!sample->first_frame_executing()) {
-        current = AppendExitFrame(sample->vm_tag(), current, sample);
-      }
-
-      sample->set_timeline_function_trie(current);
-    }
-  }
-
-  void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
-    ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie",
-                  FLAG_trace_profiler);
-    ASSERT(tick_functions_);
-    for (intptr_t sample_index = 0; sample_index < samples_->length();
-         sample_index++) {
-      ProcessedSample* sample = samples_->At(sample_index);
-
-      // Tick the root.
-      ProfileFunctionTrieNode* current = root;
-      current->Tick(sample);
-      // VM & User tags.
-      current =
-          AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
-      ResetKind();
-
-      if (!sample->first_frame_executing()) {
-        current = AppendExitFrame(sample->vm_tag(), current, sample);
-      }
-
-      // Walk the sampled PCs.
-      for (intptr_t frame_index = 0; frame_index < sample->length();
-           frame_index++) {
-        ASSERT(sample->At(frame_index) != 0);
-        current = ProcessFrame(current, sample_index, sample, frame_index);
-      }
-
-      TickExitFrameFunction(sample->vm_tag(), sample_index);
-
-      // Truncated tag.
-      if (sample->truncated()) {
-        current = AppendTruncatedTag(current, sample);
         InclusiveTickTruncatedTag(sample);
       }
     }
   }
 
-  ProfileFunctionTrieNode* ProcessFrame(ProfileFunctionTrieNode* current,
-                                        intptr_t sample_index,
-                                        ProcessedSample* sample,
-                                        intptr_t frame_index) {
+  void ProcessFrame(intptr_t sample_index,
+                    ProcessedSample* sample,
+                    intptr_t frame_index) {
     const uword pc = sample->At(frame_index);
     ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp());
     ProfileFunction* function = profile_code->function();
@@ -1625,7 +1209,7 @@
       inlined_functions_cache_.Get(pc, code, sample, frame_index,
                                    &inlined_functions, &inlined_token_positions,
                                    &token_position);
-      if (FLAG_trace_profiler_verbose) {
+      if (FLAG_trace_profiler_verbose && (inlined_functions != NULL)) {
         for (intptr_t i = 0; i < inlined_functions->length(); i++) {
           const String& name =
               String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
@@ -1643,16 +1227,9 @@
 
     if (code.IsNull() || (inlined_functions == NULL) ||
         (inlined_functions->length() <= 1)) {
-      // No inlined functions.
-      if (inclusive_tree_) {
-        current = AppendKind(code, current, sample);
-      }
-      current = ProcessFunction(current, sample_index, sample, frame_index,
-                                function, token_position, code_index);
-      if (!inclusive_tree_) {
-        current = AppendKind(code, current, sample);
-      }
-      return current;
+      ProcessFunction(sample_index, sample, frame_index, function,
+                      token_position, code_index);
+      return;
     }
 
     if (!code.is_optimized()) {
@@ -1668,99 +1245,56 @@
 
     ASSERT(code.is_optimized());
 
-    if (inclusive_tree_) {
-      for (intptr_t i = 0; i < inlined_functions->length(); i++) {
-        const Function* inlined_function = (*inlined_functions)[i];
-        ASSERT(inlined_function != NULL);
-        ASSERT(!inlined_function->IsNull());
-        TokenPosition inlined_token_position = (*inlined_token_positions)[i];
-        const bool inliner = i == 0;
-        if (inliner) {
-          current = AppendKind(code, current, sample);
-        }
-        current = ProcessInlinedFunction(current, sample_index, sample,
-                                         frame_index, inlined_function,
-                                         inlined_token_position, code_index);
-        if (inliner) {
-          current = AppendKind(kInlineStart, current, sample);
-        }
-      }
-      current = AppendKind(kInlineFinish, current, sample);
-    } else {
-      // Append the inlined children.
-      current = AppendKind(kInlineFinish, current, sample);
-      for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
-        const Function* inlined_function = (*inlined_functions)[i];
-        ASSERT(inlined_function != NULL);
-        ASSERT(!inlined_function->IsNull());
-        TokenPosition inlined_token_position = (*inlined_token_positions)[i];
-        const bool inliner = i == 0;
-        if (inliner) {
-          current = AppendKind(kInlineStart, current, sample);
-        }
-        current = ProcessInlinedFunction(current, sample_index, sample,
-                                         frame_index + i, inlined_function,
-                                         inlined_token_position, code_index);
-        if (inliner) {
-          current = AppendKind(code, current, sample);
-        }
-      }
+    // Append the inlined children.
+    for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
+      const Function* inlined_function = (*inlined_functions)[i];
+      ASSERT(inlined_function != NULL);
+      ASSERT(!inlined_function->IsNull());
+      TokenPosition inlined_token_position = (*inlined_token_positions)[i];
+      ProcessInlinedFunction(sample_index, sample, frame_index + i,
+                             inlined_function, inlined_token_position,
+                             code_index);
     }
-
-    return current;
   }
 
-  ProfileFunctionTrieNode* ProcessInlinedFunction(
-      ProfileFunctionTrieNode* current,
-      intptr_t sample_index,
-      ProcessedSample* sample,
-      intptr_t frame_index,
-      const Function* inlined_function,
-      TokenPosition inlined_token_position,
-      intptr_t code_index) {
+  void ProcessInlinedFunction(intptr_t sample_index,
+                              ProcessedSample* sample,
+                              intptr_t frame_index,
+                              const Function* inlined_function,
+                              TokenPosition inlined_token_position,
+                              intptr_t code_index) {
     ProfileFunctionTable* function_table = profile_->functions_;
     ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
     ASSERT(function != NULL);
-    return ProcessFunction(current, sample_index, sample, frame_index, function,
-                           inlined_token_position, code_index);
+    ProcessFunction(sample_index, sample, frame_index, function,
+                    inlined_token_position, code_index);
   }
 
   bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) {
     if (frame_index != 0) {
       return true;
     }
-    // Only tick the first frame's node, if we are executing OR
-    // vm tags have been emitted.
-    return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm ||
-           vm_tags_emitted();
+    // Only tick the first frame's node, if we are executing
+    return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm;
   }
 
-  ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
-                                           intptr_t sample_index,
-                                           ProcessedSample* sample,
-                                           intptr_t frame_index,
-                                           ProfileFunction* function,
-                                           TokenPosition token_position,
-                                           intptr_t code_index) {
+  void ProcessFunction(intptr_t sample_index,
+                       ProcessedSample* sample,
+                       intptr_t frame_index,
+                       ProfileFunction* function,
+                       TokenPosition token_position,
+                       intptr_t code_index) {
     if (!function->is_visible()) {
-      return current;
+      return;
     }
-    if (tick_functions_) {
-      if (FLAG_trace_profiler_verbose) {
-        THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", sample_index,
-                  frame_index, function->Name(), token_position.ToCString(),
-                  sample->At(frame_index));
-      }
-      function->Tick(IsExecutingFrame(sample, frame_index), sample_index,
-                     token_position);
+    if (FLAG_trace_profiler_verbose) {
+      THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", sample_index,
+                frame_index, function->Name(), token_position.ToCString(),
+                sample->At(frame_index));
     }
+    function->Tick(IsExecutingFrame(sample, frame_index), sample_index,
+                   token_position);
     function->AddProfileCode(code_index);
-    current = current->GetChild(function->table_index());
-    if (ShouldTickNode(sample, frame_index)) {
-      current->Tick(sample, (frame_index == 0));
-    }
-    current->AddCodeObjectIndex(code_index);
-    return current;
   }
 
   // Tick the truncated tag's inclusive tick count.
@@ -1775,70 +1309,6 @@
     function->IncInclusiveTicks();
   }
 
-  // Tag append functions are overloaded for |ProfileCodeTrieNode| and
-  // |ProfileFunctionTrieNode| types.
-
-  // ProfileCodeTrieNode
-  ProfileCodeTrieNode* AppendUserTag(uword user_tag,
-                                     ProfileCodeTrieNode* current,
-                                     ProcessedSample* sample) {
-    intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag);
-    if (user_tag_index >= 0) {
-      current = current->GetChild(user_tag_index);
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current,
-                                          ProcessedSample* sample) {
-    intptr_t truncated_tag_index =
-        GetProfileCodeTagIndex(VMTag::kTruncatedTagId);
-    ASSERT(truncated_tag_index >= 0);
-    current = current->GetChild(truncated_tag_index);
-    current->Tick(sample);
-    return current;
-  }
-
-  ProfileCodeTrieNode* AppendVMTag(uword vm_tag,
-                                   ProfileCodeTrieNode* current,
-                                   ProcessedSample* sample) {
-    if (VMTag::IsNativeEntryTag(vm_tag)) {
-      // Insert a dummy kNativeTagId node.
-      intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
-      // Insert a dummy kRuntimeTagId node.
-      intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    } else {
-      intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
-      uword vm_tag,
-      ProfileCodeTrieNode* current,
-      ProcessedSample* sample) {
-    // Only Native and Runtime entries have a second VM tag.
-    if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) {
-      return current;
-    }
-    intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
-    current = current->GetChild(tag_index);
-    // Give the tag a tick.
-    current->Tick(sample);
-    return current;
-  }
-
   uword ProfileInfoKindToVMTag(ProfileInfoKind kind) {
     switch (kind) {
       case kNone:
@@ -1859,43 +1329,6 @@
     }
   }
 
-  ProfileCodeTrieNode* AppendKind(ProfileInfoKind kind,
-                                  ProfileCodeTrieNode* current,
-                                  ProcessedSample* sample) {
-    if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
-      // Only emit if debug tags are requested.
-      return current;
-    }
-    if (kind != info_kind_) {
-      info_kind_ = kind;
-      intptr_t tag_index = GetProfileCodeTagIndex(ProfileInfoKindToVMTag(kind));
-      ASSERT(tag_index >= 0);
-      current = current->GetChild(tag_index);
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileCodeTrieNode* AppendKind(const AbstractCode code,
-                                  ProfileCodeTrieNode* current,
-                                  ProcessedSample* sample) {
-    if (code.IsNull()) {
-      return AppendKind(kNone, current, sample);
-    } else if (code.is_optimized()) {
-      return AppendKind(kOptimized, current, sample);
-    } else {
-      return AppendKind(kUnoptimized, current, sample);
-    }
-  }
-
-  ProfileCodeTrieNode* AppendVMTags(uword vm_tag,
-                                    ProfileCodeTrieNode* current,
-                                    ProcessedSample* sample) {
-    current = AppendVMTag(vm_tag, current, sample);
-    current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
-    return current;
-  }
-
   void TickExitFrame(uword vm_tag, intptr_t serial, ProcessedSample* sample) {
     if (FLAG_profile_vm) {
       return;
@@ -1924,204 +1357,6 @@
     function->Tick(true, serial, TokenPosition::kNoSource);
   }
 
-  ProfileCodeTrieNode* AppendExitFrame(uword vm_tag,
-                                       ProfileCodeTrieNode* current,
-                                       ProcessedSample* sample) {
-    if (FLAG_profile_vm) {
-      return current;
-    }
-
-    if (!VMTag::IsExitFrameTag(vm_tag)) {
-      return current;
-    }
-
-    if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) {
-      current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
-    } else {
-      intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileCodeTrieNode* AppendTags(uword vm_tag,
-                                  uword user_tag,
-                                  ProfileCodeTrieNode* current,
-                                  ProcessedSample* sample) {
-    // None.
-    if (tag_order() == Profile::kNoTags) {
-      return current;
-    }
-    // User first.
-    if ((tag_order() == Profile::kUserVM) || (tag_order() == Profile::kUser)) {
-      current = AppendUserTag(user_tag, current, sample);
-      // Only user.
-      if (tag_order() == Profile::kUser) {
-        return current;
-      }
-      return AppendVMTags(vm_tag, current, sample);
-    }
-    // VM first.
-    ASSERT((tag_order() == Profile::kVMUser) || (tag_order() == Profile::kVM));
-    current = AppendVMTags(vm_tag, current, sample);
-    // Only VM.
-    if (tag_order() == Profile::kVM) {
-      return current;
-    }
-    return AppendUserTag(user_tag, current, sample);
-  }
-
-  // ProfileFunctionTrieNode
-  void ResetKind() { info_kind_ = kNone; }
-
-  ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind,
-                                      ProfileFunctionTrieNode* current,
-                                      ProcessedSample* sample) {
-    if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
-      // Only emit if debug tags are requested.
-      return current;
-    }
-    if (kind != info_kind_) {
-      info_kind_ = kind;
-      intptr_t tag_index =
-          GetProfileFunctionTagIndex(ProfileInfoKindToVMTag(kind));
-      ASSERT(tag_index >= 0);
-      current = current->GetChild(tag_index);
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendKind(const Code& code,
-                                      ProfileFunctionTrieNode* current,
-                                      ProcessedSample* sample) {
-    if (code.IsNull()) {
-      return AppendKind(kNone, current, sample);
-    } else if (code.is_optimized()) {
-      return AppendKind(kOptimized, current, sample);
-    } else {
-      return AppendKind(kUnoptimized, current, sample);
-    }
-  }
-
-  ProfileFunctionTrieNode* AppendUserTag(uword user_tag,
-                                         ProfileFunctionTrieNode* current,
-                                         ProcessedSample* sample) {
-    intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag);
-    if (user_tag_index >= 0) {
-      current = current->GetChild(user_tag_index);
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendTruncatedTag(ProfileFunctionTrieNode* current,
-                                              ProcessedSample* sample) {
-    intptr_t truncated_tag_index =
-        GetProfileFunctionTagIndex(VMTag::kTruncatedTagId);
-    ASSERT(truncated_tag_index >= 0);
-    current = current->GetChild(truncated_tag_index);
-    current->Tick(sample);
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendVMTag(uword vm_tag,
-                                       ProfileFunctionTrieNode* current,
-                                       ProcessedSample* sample) {
-    if (VMTag::IsNativeEntryTag(vm_tag)) {
-      // Insert a dummy kNativeTagId node.
-      intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
-      // Insert a dummy kRuntimeTagId node.
-      intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    } else {
-      intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
-      uword vm_tag,
-      ProfileFunctionTrieNode* current,
-      ProcessedSample* sample) {
-    // Only Native and Runtime entries have a second VM tag.
-    if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) {
-      return current;
-    }
-    intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
-    current = current->GetChild(tag_index);
-    // Give the tag a tick.
-    current->Tick(sample);
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
-                                        ProfileFunctionTrieNode* current,
-                                        ProcessedSample* sample) {
-    current = AppendVMTag(vm_tag, current, sample);
-    current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag,
-                                           ProfileFunctionTrieNode* current,
-                                           ProcessedSample* sample) {
-    if (FLAG_profile_vm) {
-      return current;
-    }
-
-    if (!VMTag::IsExitFrameTag(vm_tag)) {
-      return current;
-    }
-    if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) {
-      current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
-    } else {
-      intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
-      current = current->GetChild(tag_index);
-      // Give the tag a tick.
-      current->Tick(sample);
-    }
-    return current;
-  }
-
-  ProfileFunctionTrieNode* AppendTags(uword vm_tag,
-                                      uword user_tag,
-                                      ProfileFunctionTrieNode* current,
-                                      ProcessedSample* sample) {
-    // None.
-    if (tag_order() == Profile::kNoTags) {
-      return current;
-    }
-    // User first.
-    if ((tag_order() == Profile::kUserVM) || (tag_order() == Profile::kUser)) {
-      current = AppendUserTag(user_tag, current, sample);
-      // Only user.
-      if (tag_order() == Profile::kUser) {
-        return current;
-      }
-      return AppendVMTags(vm_tag, current, sample);
-    }
-    // VM first.
-    ASSERT((tag_order() == Profile::kVMUser) || (tag_order() == Profile::kVM));
-    current = AppendVMTags(vm_tag, current, sample);
-    // Only VM.
-    if (tag_order() == Profile::kVM) {
-      return current;
-    }
-    return AppendUserTag(user_tag, current, sample);
-  }
-
   intptr_t GetProfileCodeTagIndex(uword tag) {
     ProfileCodeTable* tag_table = profile_->tag_code_;
     intptr_t index = tag_table->FindCodeIndexForPC(tag);
@@ -2147,30 +1382,7 @@
   }
 
   ProfileCode* GetProfileCode(uword pc, int64_t timestamp) {
-    ProfileCodeTable* live_table = profile_->live_code_;
-    ProfileCodeTable* dead_table = profile_->dead_code_;
-
-    intptr_t index = live_table->FindCodeIndexForPC(pc);
-    ProfileCode* code = NULL;
-    if (index < 0) {
-      index = dead_table->FindCodeIndexForPC(pc);
-      ASSERT(index >= 0);
-      code = dead_table->At(index);
-    } else {
-      code = live_table->At(index);
-      ASSERT(code != NULL);
-      if (code->compile_timestamp() > timestamp) {
-        // Code is newer than sample. Fall back to dead code table.
-        index = dead_table->FindCodeIndexForPC(pc);
-        ASSERT(index >= 0);
-        code = dead_table->At(index);
-      }
-    }
-
-    ASSERT(code != NULL);
-    ASSERT(code->Contains(pc));
-    ASSERT(code->compile_timestamp() <= timestamp);
-    return code;
+    return profile_->GetCodeFromPC(pc, timestamp);
   }
 
   void RegisterProfileCodeTag(uword tag) {
@@ -2292,28 +1504,14 @@
     return FindOrRegisterDeadProfileCode(pc);
   }
 
-  Profile::TagOrder tag_order() const { return tag_order_; }
-
-  bool vm_tags_emitted() const {
-    return (tag_order_ == Profile::kUserVM) ||
-           (tag_order_ == Profile::kVMUser) || (tag_order_ == Profile::kVM);
-  }
-
-  bool TagsEnabled(intptr_t extra_tags_bits) const {
-    return (extra_tags_ & extra_tags_bits) != 0;
-  }
-
   Thread* thread_;
   Isolate* vm_isolate_;
   SampleFilter* filter_;
   SampleBuffer* sample_buffer_;
-  Profile::TagOrder tag_order_;
-  intptr_t extra_tags_;
   Profile* profile_;
   DeoptimizedCodeSet* deoptimized_code_;
   const AbstractCode null_code_;
   const Function& null_function_;
-  bool tick_functions_;
   bool inclusive_tree_;
   ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
   ProcessedSampleBuffer* samples_;
@@ -2333,21 +1531,21 @@
       min_time_(kMaxInt64),
       max_time_(0) {
   ASSERT(isolate_ != NULL);
-  for (intptr_t i = 0; i < kNumTrieKinds; i++) {
-    roots_[i] = NULL;
-  }
 }
 
 void Profile::Build(Thread* thread,
                     SampleFilter* filter,
-                    SampleBuffer* sample_buffer,
-                    TagOrder tag_order,
-                    intptr_t extra_tags) {
-  ProfileBuilder builder(thread, filter, sample_buffer, tag_order, extra_tags,
-                         this);
+                    SampleBuffer* sample_buffer) {
+  ProfileBuilder builder(thread, filter, sample_buffer, this);
   builder.Build();
 }
 
+ProcessedSample* Profile::SampleAt(intptr_t index) {
+  ASSERT(index >= 0);
+  ASSERT(index < sample_count_);
+  return samples_->At(index);
+}
+
 intptr_t Profile::NumFunctions() const {
   return functions_->length();
 }
@@ -2382,21 +1580,44 @@
   return tag_code_->At(index);
 }
 
-ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) {
-  return roots_[static_cast<intptr_t>(trie_kind)];
+ProfileCode* Profile::GetCodeFromPC(uword pc, int64_t timestamp) {
+  intptr_t index = live_code_->FindCodeIndexForPC(pc);
+  ProfileCode* code = NULL;
+  if (index < 0) {
+    index = dead_code_->FindCodeIndexForPC(pc);
+    ASSERT(index >= 0);
+    code = dead_code_->At(index);
+  } else {
+    code = live_code_->At(index);
+    ASSERT(code != NULL);
+    if (code->compile_timestamp() > timestamp) {
+      // Code is newer than sample. Fall back to dead code table.
+      index = dead_code_->FindCodeIndexForPC(pc);
+      ASSERT(index >= 0);
+      code = dead_code_->At(index);
+    }
+  }
+
+  ASSERT(code != NULL);
+  ASSERT(code->Contains(pc));
+  ASSERT(code->compile_timestamp() <= timestamp);
+  return code;
 }
 
 void Profile::PrintHeaderJSON(JSONObject* obj) {
+  intptr_t pid = OS::ProcessId();
+
   obj->AddProperty("samplePeriod", static_cast<intptr_t>(FLAG_profile_period));
-  obj->AddProperty("stackDepth", static_cast<intptr_t>(FLAG_max_profile_depth));
+  obj->AddProperty("maxStackDepth",
+                   static_cast<intptr_t>(FLAG_max_profile_depth));
   obj->AddProperty("sampleCount", sample_count());
-  obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
+  obj->AddProperty("timespan", MicrosecondsToSeconds(GetTimeSpan()));
   obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
   obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
-
+  obj->AddProperty64("pid", pid);
   ProfilerCounters counters = Profiler::counters();
   {
-    JSONObject counts(obj, "counters");
+    JSONObject counts(obj, "_counters");
     counts.AddProperty64("bail_out_unknown_task",
                          counters.bail_out_unknown_task);
     counts.AddProperty64("bail_out_jump_to_exception_handler",
@@ -2418,154 +1639,144 @@
   }
 }
 
-static const intptr_t kRootFrameId = 0;
+void Profile::ProcessSampleFrameJSON(JSONArray* stack,
+                                     ProfileCodeInlinedFunctionsCache* cache_,
+                                     ProcessedSample* sample,
+                                     intptr_t frame_index) {
+  const uword pc = sample->At(frame_index);
+  ProfileCode* profile_code = GetCodeFromPC(pc, sample->timestamp());
+  ASSERT(profile_code != NULL);
+  ProfileFunction* function = profile_code->function();
+  ASSERT(function != NULL);
 
-void Profile::PrintTimelineFrameJSON(JSONObject* frames,
-                                     ProfileTrieNode* current,
-                                     ProfileTrieNode* parent,
-                                     intptr_t* next_id,
-                                     bool code_trie) {
-  ASSERT(current->frame_id() == -1);
-  const intptr_t id = *next_id;
-  *next_id = id + 1;
-  current->set_frame_id(id);
-  ASSERT(current->frame_id() != -1);
-
-  if (id != kRootFrameId) {
-    // The samples from many isolates may be merged into a single timeline,
-    // so prefix frames id with the isolate.
-    intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_);
-    const char* key =
-        zone_->PrintToString("%" Pd "-%" Pd, isolate_id, current->frame_id());
-    JSONObject frame(frames, key);
-    frame.AddProperty("category", "Dart");
-    if (code_trie) {
-      ProfileCode* code = GetCode(current->table_index());
-      frame.AddProperty("name", code->name());
-      const char* resolved_script_url = NULL;
-      if (code->function() != NULL) {
-        resolved_script_url = code->function()->ResolvedScriptUrl();
-      }
-      frame.AddProperty("resolvedUrl", resolved_script_url);
-    } else {
-      ProfileFunction* func = GetFunction(current->table_index());
-      frame.AddProperty("name", func->Name());
-      frame.AddProperty("resolvedUrl", func->ResolvedScriptUrl());
-    }
-    if ((parent != NULL) && (parent->frame_id() != kRootFrameId)) {
-      ASSERT(parent->frame_id() != -1);
-      frame.AddPropertyF("parent", "%" Pd "-%" Pd, isolate_id,
-                         parent->frame_id());
-    }
-  }
-
-  for (intptr_t i = 0; i < current->NumChildren(); i++) {
-    ProfileTrieNode* child = current->At(i);
-    PrintTimelineFrameJSON(frames, child, current, next_id, code_trie);
-  }
-}
-
-void Profile::PrintTimelineJSON(JSONStream* stream, bool code_trie) {
-  ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler);
-  JSONObject obj(stream);
-  obj.AddProperty("type", "_CpuProfileTimeline");
-  PrintHeaderJSON(&obj);
-  {
-    JSONObject frames(&obj, "stackFrames");
-    ProfileTrieNode* root;
-    if (code_trie) {
-      root = GetTrieRoot(kInclusiveCode);
-    } else {
-      root = GetTrieRoot(kInclusiveFunction);
-    }
-    intptr_t next_id = kRootFrameId;
-    PrintTimelineFrameJSON(&frames, root, NULL, &next_id, code_trie);
-  }
-  {
-    JSONArray events(&obj, "traceEvents");
-    intptr_t pid = OS::ProcessId();
-    intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_);
-    for (intptr_t sample_index = 0; sample_index < samples_->length();
-         sample_index++) {
-      ProcessedSample* sample = samples_->At(sample_index);
-      ProfileTrieNode* trie;
-      if (code_trie) {
-        trie = sample->timeline_code_trie();
-      } else {
-        trie = sample->timeline_function_trie();
-      }
-      ASSERT(trie->frame_id() != -1);
-
-      if (trie->frame_id() != kRootFrameId) {
-        JSONObject event(&events);
-        event.AddProperty("ph", "P");  // kind = sample event
-        // Add a blank name to keep about:tracing happy.
-        event.AddProperty("name", "");
-        event.AddProperty64("pid", pid);
-        event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid()));
-        event.AddPropertyTimeMicros("ts", sample->timestamp());
-        event.AddProperty("cat", "Dart");
-        if (!Isolate::IsVMInternalIsolate(isolate_)) {
-          JSONObject args(&event, "args");
-          args.AddProperty("mode", "basic");
-        }
-        event.AddPropertyF("sf", "%" Pd "-%" Pd, isolate_id, trie->frame_id());
-      }
-    }
-  }
-}
-
-void Profile::AddParentTriePointers(ProfileTrieNode* current,
-                                    ProfileTrieNode* parent,
-                                    bool code_trie) {
-  if (current == NULL) {
-    ProfileTrieNode* root;
-    if (code_trie) {
-      root = GetTrieRoot(kInclusiveCode);
-    } else {
-      root = GetTrieRoot(kInclusiveFunction);
-    }
-    AddParentTriePointers(root, NULL, code_trie);
+  // Don't show stubs in stack traces.
+  if (!function->is_visible() ||
+      (function->kind() == ProfileFunction::kStubFunction)) {
     return;
   }
 
-  current->set_parent(parent);
-  for (int i = 0; i < current->NumChildren(); i++) {
-    AddParentTriePointers(current->At(i), current, code_trie);
-  }
-}
+  GrowableArray<const Function*>* inlined_functions = NULL;
+  GrowableArray<TokenPosition>* inlined_token_positions = NULL;
+  TokenPosition token_position = TokenPosition::kNoSource;
+  Code& code = Code::ZoneHandle();
 
-void Profile::PrintBacktrace(ProfileTrieNode* node, TextBuffer* buf) {
-  ProfileTrieNode* current = node;
-  while (current != NULL) {
-    buf->AddString(current->ToCString(this));
-    buf->AddString("\n");
-    current = current->parent();
+  if (profile_code->code().IsCode()) {
+    code ^= profile_code->code().raw();
+    cache_->Get(pc, code, sample, frame_index, &inlined_functions,
+                &inlined_token_positions, &token_position);
+    if (FLAG_trace_profiler_verbose && (inlined_functions != NULL)) {
+      for (intptr_t i = 0; i < inlined_functions->length(); i++) {
+        const String& name =
+            String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
+        THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", i, name.ToCString(),
+                  (*inlined_token_positions)[i].ToCString());
+      }
+    }
+  } else if (profile_code->code().IsBytecode()) {
+    // No inlining in bytecode.
+    const Bytecode& bc = Bytecode::CheckedHandle(Thread::Current()->zone(),
+                                                 profile_code->code().raw());
+    token_position = bc.GetTokenIndexOfPC(pc);
   }
-}
 
-void Profile::AddToTimeline(bool code_trie) {
-  TimelineStream* stream = Timeline::GetProfilerStream();
-  if (stream == NULL) {
+  if (code.IsNull() || (inlined_functions == NULL) ||
+      (inlined_functions->length() <= 1)) {
+    PrintFunctionFrameIndexJSON(stack, function);
     return;
   }
-  AddParentTriePointers(NULL, NULL, code_trie);
+
+  if (!code.is_optimized()) {
+    OS::PrintErr("Code that should be optimized is not. Please file a bug\n");
+    OS::PrintErr("Code object: %s\n", code.ToCString());
+    OS::PrintErr("Inlined functions length: %" Pd "\n",
+                 inlined_functions->length());
+    for (intptr_t i = 0; i < inlined_functions->length(); i++) {
+      OS::PrintErr("IF[%" Pd "] = %s\n", i,
+                   (*inlined_functions)[i]->ToFullyQualifiedCString());
+    }
+  }
+
+  ASSERT(code.is_optimized());
+
+  for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
+    const Function* inlined_function = (*inlined_functions)[i];
+    ASSERT(inlined_function != NULL);
+    ASSERT(!inlined_function->IsNull());
+    ProcessInlinedFunctionFrameJSON(stack, inlined_function);
+  }
+}
+
+void Profile::ProcessInlinedFunctionFrameJSON(
+    JSONArray* stack,
+    const Function* inlined_function) {
+  ProfileFunction* function = functions_->LookupOrAdd(*inlined_function);
+  ASSERT(function != NULL);
+  PrintFunctionFrameIndexJSON(stack, function);
+}
+
+void Profile::PrintFunctionFrameIndexJSON(JSONArray* stack,
+                                          ProfileFunction* function) {
+  stack->AddValue64(function->table_index());
+}
+
+void Profile::PrintCodeFrameIndexJSON(JSONArray* stack,
+                                      ProcessedSample* sample,
+                                      intptr_t frame_index) {
+  ProfileCode* code =
+      GetCodeFromPC(sample->At(frame_index), sample->timestamp());
+  const AbstractCode codeObj = code->code();
+
+  // Ignore stub code objects.
+  if (codeObj.IsStubCode() || codeObj.IsAllocationStubCode() ||
+      codeObj.IsTypeTestStubCode()) {
+    return;
+  }
+  stack->AddValue64(code->code_table_index());
+}
+
+void Profile::PrintSamplesJSON(JSONObject* obj, bool code_samples) {
+  JSONArray samples(obj, "samples");
+  ProfileCodeInlinedFunctionsCache cache;
   for (intptr_t sample_index = 0; sample_index < samples_->length();
        sample_index++) {
-    TextBuffer buf(256);
+    JSONObject sample_obj(&samples);
     ProcessedSample* sample = samples_->At(sample_index);
-    if (code_trie) {
-      PrintBacktrace(sample->timeline_code_trie(), &buf);
-    } else {
-      PrintBacktrace(sample->timeline_function_trie(), &buf);
+    sample_obj.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid()));
+    sample_obj.AddPropertyTimeMicros("timestamp", sample->timestamp());
+    sample_obj.AddProperty("vmTag", VMTag::TagName(sample->vm_tag()));
+    if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
+      sample_obj.AddProperty("nativeEntryTag", true);
     }
-    TimelineEvent* event = stream->StartEvent();
-    event->Instant("Dart CPU sample", sample->timestamp());
-    event->set_owns_label(false);
-    event->SetNumArguments(1);
-    event->SetArgument(0, "backtrace", buf.Steal());
-    event->Complete();
-    event = NULL;  // Complete() deletes the event.
+    if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
+      sample_obj.AddProperty("runtimeEntryTag", true);
+    }
+    if (UserTags::IsUserTag(sample->user_tag())) {
+      sample_obj.AddProperty("userTag", UserTags::TagName(sample->user_tag()));
+    }
+    if (sample->truncated()) {
+      sample_obj.AddProperty("truncated", true);
+    }
+    if (sample->is_native_allocation_sample()) {
+      sample_obj.AddProperty64("_nativeAllocationSizeBytes",
+                               sample->native_allocation_size_bytes());
+    }
+    {
+      JSONArray stack(&sample_obj, "stack");
+      // Walk the sampled PCs.
+      for (intptr_t frame_index = 0; frame_index < sample->length();
+           frame_index++) {
+        ASSERT(sample->At(frame_index) != 0);
+        ProcessSampleFrameJSON(&stack, &cache, sample, frame_index);
+      }
+    }
+    if (code_samples) {
+      JSONArray stack(&sample_obj, "_codeStack");
+      for (intptr_t frame_index = 0; frame_index < sample->length();
+           frame_index++) {
+        ASSERT(sample->At(frame_index) != 0);
+        PrintCodeFrameIndexJSON(&stack, sample, frame_index);
+      }
+    }
   }
 }
 
@@ -2573,13 +1784,13 @@
   return (functions_ != NULL) ? functions_->Lookup(function) : NULL;
 }
 
-void Profile::PrintProfileJSON(JSONStream* stream) {
+void Profile::PrintProfileJSON(JSONStream* stream, bool include_code_samples) {
   ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler);
   JSONObject obj(stream);
-  obj.AddProperty("type", "_CpuProfile");
+  obj.AddProperty("type", "CpuSamples");
   PrintHeaderJSON(&obj);
-  {
-    JSONArray codes(&obj, "codes");
+  if (include_code_samples) {
+    JSONArray codes(&obj, "_codes");
     for (intptr_t i = 0; i < live_code_->length(); i++) {
       ProfileCode* code = live_code_->At(i);
       ASSERT(code != NULL);
@@ -2605,217 +1816,26 @@
       function->PrintToJSONArray(&functions);
     }
   }
-  {
-    JSONArray code_trie(&obj, "exclusiveCodeTrie");
-    ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveCode)];
-    ASSERT(root != NULL);
-    root->PrintToJSONArray(&code_trie);
-  }
-  {
-    JSONArray code_trie(&obj, "inclusiveCodeTrie");
-    ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveCode)];
-    ASSERT(root != NULL);
-    root->PrintToJSONArray(&code_trie);
-  }
-  {
-    JSONArray function_trie(&obj, "exclusiveFunctionTrie");
-    ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveFunction)];
-    ASSERT(root != NULL);
-    root->PrintToJSONArray(&function_trie);
-  }
-  {
-    JSONArray function_trie(&obj, "inclusiveFunctionTrie");
-    ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)];
-    ASSERT(root != NULL);
-    root->PrintToJSONArray(&function_trie);
-  }
-  {
-    ProfilerCounters counters = Profiler::counters();
-    JSONObject js_counters(&obj, "counters");
-#define ADD_PROFILER_COUNTER(name)                                             \
-    js_counters.AddProperty64("" #name, counters.name);
-PROFILER_COUNTERS(ADD_PROFILER_COUNTER)
-#undef ADD_PROFILER_COUNTER
-  }
-}
-
-void ProfileTrieWalker::Reset(Profile::TrieKind trie_kind) {
-  code_trie_ = Profile::IsCodeTrie(trie_kind);
-  parent_ = NULL;
-  current_ = profile_->GetTrieRoot(trie_kind);
-  ASSERT(current_ != NULL);
-}
-
-const char* ProfileTrieWalker::CurrentName() {
-  if (current_ == NULL) {
-    return NULL;
-  }
-  if (code_trie_) {
-    ProfileCode* code = profile_->GetCode(current_->table_index());
-    return code->name();
-  } else {
-    ProfileFunction* func = profile_->GetFunction(current_->table_index());
-    return func->Name();
-  }
-  UNREACHABLE();
-  return NULL;
-}
-
-intptr_t ProfileTrieWalker::CurrentNodeTickCount() {
-  if (current_ == NULL) {
-    return -1;
-  }
-  return current_->count();
-}
-
-intptr_t ProfileTrieWalker::CurrentInclusiveTicks() {
-  if (current_ == NULL) {
-    return -1;
-  }
-  if (code_trie_) {
-    ProfileCode* code = profile_->GetCode(current_->table_index());
-    return code->inclusive_ticks();
-  } else {
-    ProfileFunction* func = profile_->GetFunction(current_->table_index());
-    return func->inclusive_ticks();
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-intptr_t ProfileTrieWalker::CurrentExclusiveTicks() {
-  if (current_ == NULL) {
-    return -1;
-  }
-  if (code_trie_) {
-    ProfileCode* code = profile_->GetCode(current_->table_index());
-    return code->exclusive_ticks();
-  } else {
-    ProfileFunction* func = profile_->GetFunction(current_->table_index());
-    return func->exclusive_ticks();
-  }
-  UNREACHABLE();
-  return -1;
-}
-
-intptr_t ProfileTrieWalker::CurrentInclusiveAllocations() {
-  if (current_ == NULL) {
-    return -1;
-  }
-  return current_->inclusive_allocations();
-}
-
-intptr_t ProfileTrieWalker::CurrentExclusiveAllocations() {
-  if (current_ == NULL) {
-    return -1;
-  }
-  return current_->exclusive_allocations();
-}
-
-const char* ProfileTrieWalker::CurrentToken() {
-  if (current_ == NULL) {
-    return NULL;
-  }
-  if (code_trie_) {
-    return NULL;
-  }
-  ProfileFunction* func = profile_->GetFunction(current_->table_index());
-  const Function& function = *(func->function());
-  if (function.IsNull()) {
-    // No function.
-    return NULL;
-  }
-  Zone* zone = Thread::Current()->zone();
-  const Script& script = Script::Handle(zone, function.script());
-  if (script.IsNull()) {
-    // No script.
-    return NULL;
-  }
-  ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
-  if (!func->GetSinglePosition(&pfsp)) {
-    // Not exactly one source position.
-    return NULL;
-  }
-  TokenPosition token_pos = pfsp.token_pos();
-  if (!token_pos.IsSourcePosition()) {
-    // Not a location in a script.
-    return NULL;
-  }
-  if (token_pos.IsSynthetic()) {
-    token_pos = token_pos.FromSynthetic();
-  }
-
-  String& str = String::Handle(zone);
-  if (script.kind() == RawScript::kKernelTag) {
-    intptr_t line = 0, column = 0, token_len = 0;
-    script.GetTokenLocation(token_pos, &line, &column, &token_len);
-    str = script.GetSnippet(line, column, line, column + token_len);
-  } else {
-    UNREACHABLE();
-  }
-  return str.IsNull() ? NULL : str.ToCString();
-}
-
-bool ProfileTrieWalker::Down() {
-  if ((current_ == NULL) || (current_->NumChildren() == 0)) {
-    return false;
-  }
-  parent_ = current_;
-  current_ = current_->At(0);
-  return true;
-}
-
-bool ProfileTrieWalker::NextSibling() {
-  if (parent_ == NULL) {
-    return false;
-  }
-  intptr_t current_index = parent_->IndexOf(current_);
-  if (current_index < 0) {
-    return false;
-  }
-  current_index++;
-  if (current_index >= parent_->NumChildren()) {
-    return false;
-  }
-  current_ = parent_->At(current_index);
-  return true;
-}
-
-intptr_t ProfileTrieWalker::SiblingCount() {
-  ASSERT(parent_ != NULL);
-  return parent_->NumChildren();
+  PrintSamplesJSON(&obj, include_code_samples);
 }
 
 void ProfilerService::PrintJSONImpl(Thread* thread,
                                     JSONStream* stream,
-                                    Profile::TagOrder tag_order,
-                                    intptr_t extra_tags,
                                     SampleFilter* filter,
                                     SampleBuffer* sample_buffer,
-                                    PrintKind kind,
-                                    bool code_trie) {
+                                    bool include_code_samples) {
   Isolate* isolate = thread->isolate();
   // Disable thread interrupts while processing the buffer.
   DisableThreadInterruptsScope dtis(thread);
 
-  if (sample_buffer == NULL) {
-    stream->PrintError(kFeatureDisabled, NULL);
-    return;
-  }
+  // We should bail out in service.cc if the profiler is disabled.
+  ASSERT(sample_buffer != NULL);
 
-  {
-    StackZone zone(thread);
-    HANDLESCOPE(thread);
-    Profile profile(isolate);
-    profile.Build(thread, filter, sample_buffer, tag_order, extra_tags);
-    if (kind == kAsTimeline) {
-      profile.PrintTimelineJSON(stream, code_trie);
-    } else if (kind == kAsProfile) {
-      profile.PrintProfileJSON(stream);
-    } else if (kind == kAsPlatformTimeline) {
-      profile.AddToTimeline(code_trie);
-    }
-  }
+  StackZone zone(thread);
+  HANDLESCOPE(thread);
+  Profile profile(isolate);
+  profile.Build(thread, filter, sample_buffer);
+  profile.PrintProfileJSON(stream, include_code_samples);
 }
 
 class NoAllocationSampleFilter : public SampleFilter {
@@ -2833,17 +1853,15 @@
 };
 
 void ProfilerService::PrintJSON(JSONStream* stream,
-                                Profile::TagOrder tag_order,
-                                intptr_t extra_tags,
                                 int64_t time_origin_micros,
-                                int64_t time_extent_micros) {
+                                int64_t time_extent_micros,
+                                bool include_code_samples) {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   NoAllocationSampleFilter filter(isolate->main_port(), Thread::kMutatorTask,
                                   time_origin_micros, time_extent_micros);
-  bool code_trie = false;  // Doesn't matter for kAsProfile.
-  PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter,
-                Profiler::sample_buffer(), kAsProfile, code_trie);
+  PrintJSONImpl(thread, stream, &filter, Profiler::sample_buffer(),
+                include_code_samples);
 }
 
 class ClassAllocationSampleFilter : public SampleFilter {
@@ -2871,7 +1889,6 @@
 };
 
 void ProfilerService::PrintAllocationJSON(JSONStream* stream,
-                                          Profile::TagOrder tag_order,
                                           const Class& cls,
                                           int64_t time_origin_micros,
                                           int64_t time_extent_micros) {
@@ -2880,52 +1897,17 @@
   ClassAllocationSampleFilter filter(isolate->main_port(), cls,
                                      Thread::kMutatorTask, time_origin_micros,
                                      time_extent_micros);
-  bool code_trie = false;  // Doesn't matter for kAsProfile.
-  PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
-                Profiler::sample_buffer(), kAsProfile, code_trie);
+  PrintJSONImpl(thread, stream, &filter, Profiler::sample_buffer(), true);
 }
 
 void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream,
-                                                Profile::TagOrder tag_order,
                                                 int64_t time_origin_micros,
-                                                int64_t time_extent_micros) {
+                                                int64_t time_extent_micros,
+                                                bool include_code_samples) {
   Thread* thread = Thread::Current();
   NativeAllocationSampleFilter filter(time_origin_micros, time_extent_micros);
-  bool code_trie = false;  // Doesn't matter for kAsProfile.
-  PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
-                Profiler::allocation_sample_buffer(), kAsProfile, code_trie);
-}
-
-void ProfilerService::PrintTimelineJSON(JSONStream* stream,
-                                        Profile::TagOrder tag_order,
-                                        int64_t time_origin_micros,
-                                        int64_t time_extent_micros,
-                                        bool code_trie) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  const intptr_t thread_task_mask = Thread::kMutatorTask |
-                                    Thread::kCompilerTask |
-                                    Thread::kSweeperTask | Thread::kMarkerTask;
-  NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask,
-                                  time_origin_micros, time_extent_micros);
-  PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
-                Profiler::sample_buffer(), kAsTimeline, code_trie);
-}
-
-void ProfilerService::AddToTimeline(Profile::TagOrder tag_order,
-                                    int64_t time_origin_micros,
-                                    int64_t time_extent_micros,
-                                    bool code_trie) {
-  JSONStream stream;
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  const intptr_t thread_task_mask = Thread::kMutatorTask |
-                                    Thread::kCompilerTask |
-                                    Thread::kSweeperTask | Thread::kMarkerTask;
-  NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask,
-                                  time_origin_micros, time_extent_micros);
-  PrintJSONImpl(thread, &stream, Profile::kNoTags, kNoExtraTags, &filter,
-                Profiler::sample_buffer(), kAsPlatformTimeline, code_trie);
+  PrintJSONImpl(thread, stream, &filter, Profiler::allocation_sample_buffer(),
+                include_code_samples);
 }
 
 void ProfilerService::ClearSamples() {
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index 9328800..8460af8 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -53,6 +53,81 @@
   DISALLOW_ALLOCATION();
 };
 
+class ProfileCodeInlinedFunctionsCache : public ValueObject {
+ public:
+  ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) {
+    for (intptr_t i = 0; i < kCacheSize; i++) {
+      cache_[i].Reset();
+    }
+    cache_hit_ = 0;
+    cache_miss_ = 0;
+  }
+
+  ~ProfileCodeInlinedFunctionsCache() {
+    if (FLAG_trace_profiler) {
+      intptr_t total = cache_hit_ + cache_miss_;
+      OS::PrintErr("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total,
+                   cache_hit_, cache_miss_);
+    }
+  }
+
+  void Get(uword pc,
+           const Code& code,
+           ProcessedSample* sample,
+           intptr_t frame_index,
+           // Outputs:
+           GrowableArray<const Function*>** inlined_functions,
+           GrowableArray<TokenPosition>** inlined_token_positions,
+           TokenPosition* token_position);
+
+ private:
+  bool FindInCache(uword pc,
+                   intptr_t offset,
+                   GrowableArray<const Function*>** inlined_functions,
+                   GrowableArray<TokenPosition>** inlined_token_positions,
+                   TokenPosition* token_position);
+
+  // Add to cache and fill in outputs.
+  void Add(uword pc,
+           const Code& code,
+           ProcessedSample* sample,
+           intptr_t frame_index,
+           // Outputs:
+           GrowableArray<const Function*>** inlined_functions,
+           GrowableArray<TokenPosition>** inlined_token_positions,
+           TokenPosition* token_position);
+
+  intptr_t NextFreeIndex() {
+    cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
+    return cache_cursor_;
+  }
+
+  intptr_t OffsetForPC(uword pc,
+                       const Code& code,
+                       ProcessedSample* sample,
+                       intptr_t frame_index);
+  struct CacheEntry {
+    void Reset() {
+      pc = 0;
+      offset = 0;
+      inlined_functions.Clear();
+      inlined_token_positions.Clear();
+    }
+    uword pc;
+    intptr_t offset;
+    GrowableArray<const Function*> inlined_functions;
+    GrowableArray<TokenPosition> inlined_token_positions;
+    TokenPosition token_position;
+  };
+
+  static const intptr_t kCacheSize = 128;
+  intptr_t cache_cursor_;
+  intptr_t last_hit_;
+  CacheEntry cache_[kCacheSize];
+  intptr_t cache_miss_;
+  intptr_t cache_hit_;
+};
+
 // Profile data related to a |Function|.
 class ProfileFunction : public ZoneAllocated {
  public:
@@ -213,6 +288,8 @@
 
   ProfileFunction* function() const { return function_; }
 
+  intptr_t code_table_index() const { return code_table_index_; }
+
  private:
   void Tick(uword pc, bool exclusive, intptr_t serial);
   void TickAddress(uword pc, bool exclusive);
@@ -225,7 +302,6 @@
   void PrintTagCode(JSONObject* profile_code_obj);
 
   void set_code_table_index(intptr_t index) { code_table_index_ = index; }
-  intptr_t code_table_index() const { return code_table_index_; }
 
   const Kind kind_;
   uword start_;
@@ -285,137 +361,46 @@
   ZoneGrowableArray<ProfileCode*> table_;
 };
 
-// Stack traces are organized in a trie. This holds information about one node
-// in the trie. A node in a tree represents a stack frame and a path in the tree
-// represents a stack trace. Each unique stack trace appears in the tree once
-// and each node has a count indicating how many times this has been observed.
-// The index can be used to look up a |ProfileFunction| or |ProfileCode|.
-// A node can have zero or more children. Depending on the kind of trie the
-// children are callers or callees of the current node.
-class ProfileTrieNode : public ZoneAllocated {
- public:
-  explicit ProfileTrieNode(intptr_t index);
-  virtual ~ProfileTrieNode();
-
-  virtual void PrintToJSONArray(JSONArray* array) const = 0;
-
-  virtual const char* ToCString(Profile* profile) const = 0;
-
-  // Index into function or code tables.
-  intptr_t table_index() const { return table_index_; }
-
-  intptr_t count() const { return count_; }
-
-  void Tick(ProcessedSample* sample, bool exclusive = false);
-
-  void IncrementAllocation(intptr_t allocation, bool exclusive) {
-    ASSERT(allocation >= 0);
-    if (exclusive) {
-      exclusive_allocations_ += allocation;
-    }
-    inclusive_allocations_ += allocation;
-  }
-
-  intptr_t inclusive_allocations() const { return inclusive_allocations_; }
-  intptr_t exclusive_allocations() const { return exclusive_allocations_; }
-
-  intptr_t NumChildren() const { return children_.length(); }
-
-  ProfileTrieNode* At(intptr_t i) { return children_.At(i); }
-
-  ProfileTrieNode* parent() const { return parent_; }
-  void set_parent(ProfileTrieNode* p) { parent_ = p; }
-
-  intptr_t IndexOf(ProfileTrieNode* node);
-
-  intptr_t frame_id() const { return frame_id_; }
-  void set_frame_id(intptr_t id) {
-    ASSERT(frame_id_ == -1);
-    frame_id_ = id;
-  }
-
- protected:
-  void SortChildren();
-
-  static int ProfileTrieNodeCompare(ProfileTrieNode* const* a,
-                                    ProfileTrieNode* const* b) {
-    ASSERT(a != NULL);
-    ASSERT(b != NULL);
-    return (*b)->count() - (*a)->count();
-  }
-
-  intptr_t table_index_;
-  intptr_t count_;
-  intptr_t exclusive_allocations_;
-  intptr_t inclusive_allocations_;
-  ZoneGrowableArray<ProfileTrieNode*> children_;
-  ProfileTrieNode* parent_;
-  intptr_t frame_id_;
-
-  friend class ProfileBuilder;
-};
 
 // The model for a profile. Most of the model is zone allocated, therefore
 // a zone must be created that lives longer than this object.
 class Profile : public ValueObject {
  public:
-  enum TagOrder { kNoTags, kUser, kUserVM, kVM, kVMUser };
-
-  enum TrieKind {
-    kExclusiveCode,
-    kExclusiveFunction,
-    kInclusiveCode,
-    kInclusiveFunction,
-    kNumTrieKinds,
-  };
-
-  static bool IsCodeTrie(TrieKind kind) {
-    return (kind == kExclusiveCode) || (kind == kInclusiveCode);
-  }
-
-  static bool IsFunctionTrie(TrieKind kind) { return !IsCodeTrie(kind); }
-
   explicit Profile(Isolate* isolate);
 
-  // Build a filtered model using |filter| with the specified |tag_order|.
-  void Build(Thread* thread,
-             SampleFilter* filter,
-             SampleBuffer* sample_buffer,
-             TagOrder tag_order,
-             intptr_t extra_tags = 0);
+  // Build a filtered model using |filter|.
+  void Build(Thread* thread, SampleFilter* filter, SampleBuffer* sample_buffer);
 
   // After building:
   int64_t min_time() const { return min_time_; }
   int64_t max_time() const { return max_time_; }
   int64_t GetTimeSpan() const { return max_time() - min_time(); }
   intptr_t sample_count() const { return sample_count_; }
+  ProcessedSample* SampleAt(intptr_t index);
 
   intptr_t NumFunctions() const;
 
   ProfileFunction* GetFunction(intptr_t index);
   ProfileCode* GetCode(intptr_t index);
-  ProfileTrieNode* GetTrieRoot(TrieKind trie_kind);
+  ProfileCode* GetCodeFromPC(uword pc, int64_t timestamp);
 
-  void PrintProfileJSON(JSONStream* stream);
-  void PrintTimelineJSON(JSONStream* stream, bool code_trie);
-
-  // Serializes sample backtraces into arguments on Instant events and adds them
-  // directly to the timeline.
-  void AddToTimeline(bool code_trie);
+  void PrintProfileJSON(JSONStream* stream, bool include_code_samples);
 
   ProfileFunction* FindFunction(const Function& function);
 
  private:
-  void AddParentTriePointers(ProfileTrieNode* current,
-                             ProfileTrieNode* parent,
-                             bool code_trie);
-  void PrintBacktrace(ProfileTrieNode* node, TextBuffer* buf);
   void PrintHeaderJSON(JSONObject* obj);
-  void PrintTimelineFrameJSON(JSONObject* frames,
-                              ProfileTrieNode* current,
-                              ProfileTrieNode* parent,
-                              intptr_t* next_id,
-                              bool code_trie);
+  void ProcessSampleFrameJSON(JSONArray* stack,
+                              ProfileCodeInlinedFunctionsCache* cache,
+                              ProcessedSample* sample,
+                              intptr_t frame_index);
+  void ProcessInlinedFunctionFrameJSON(JSONArray* stack,
+                                       const Function* inlined_function);
+  void PrintFunctionFrameIndexJSON(JSONArray* stack, ProfileFunction* function);
+  void PrintCodeFrameIndexJSON(JSONArray* stack,
+                               ProcessedSample* sample,
+                               intptr_t frame_index);
+  void PrintSamplesJSON(JSONObject* obj, bool code_samples);
 
   Isolate* isolate_;
   Zone* zone_;
@@ -427,8 +412,6 @@
   intptr_t dead_code_index_offset_;
   intptr_t tag_code_index_offset_;
 
-  ProfileTrieNode* roots_[kNumTrieKinds];
-
   int64_t min_time_;
   int64_t max_time_;
 
@@ -437,97 +420,31 @@
   friend class ProfileBuilder;
 };
 
-class ProfileTrieWalker : public ValueObject {
- public:
-  explicit ProfileTrieWalker(Profile* profile)
-      : profile_(profile), parent_(NULL), current_(NULL), code_trie_(false) {
-    ASSERT(profile_ != NULL);
-  }
-
-  void Reset(Profile::TrieKind trie_kind);
-
-  const char* CurrentName();
-  // Return the current node's peer's inclusive tick count.
-  intptr_t CurrentInclusiveTicks();
-  // Return the current node's peer's exclusive tick count.
-  intptr_t CurrentExclusiveTicks();
-  // Return the current node's inclusive allocation count.
-  intptr_t CurrentInclusiveAllocations();
-  // Return the current node's exclusive allocation count.
-  intptr_t CurrentExclusiveAllocations();
-  // Return the current node's tick count.
-  intptr_t CurrentNodeTickCount();
-  // Return the number siblings (including yourself).
-  intptr_t SiblingCount();
-
-  // If the following conditions are met returns the current token:
-  // 1) This is a function trie.
-  // 2) There is only one token position for a given function.
-  // Will return NULL otherwise.
-  const char* CurrentToken();
-
-  bool Down();
-  bool NextSibling();
-
- private:
-  Profile* profile_;
-  ProfileTrieNode* parent_;
-  ProfileTrieNode* current_;
-  bool code_trie_;
-};
-
 class ProfilerService : public AllStatic {
  public:
-  enum {
-    kNoExtraTags = 0,
-    kCodeTransitionTagsBit = (1 << 0),
-  };
-
   static void PrintJSON(JSONStream* stream,
-                        Profile::TagOrder tag_order,
-                        intptr_t extra_tags,
                         int64_t time_origin_micros,
-                        int64_t time_extent_micros);
+                        int64_t time_extent_micros,
+                        bool include_code_samples);
 
   static void PrintAllocationJSON(JSONStream* stream,
-                                  Profile::TagOrder tag_order,
                                   const Class& cls,
                                   int64_t time_origin_micros,
                                   int64_t time_extent_micros);
 
   static void PrintNativeAllocationJSON(JSONStream* stream,
-                                        Profile::TagOrder tag_order,
                                         int64_t time_origin_micros,
-                                        int64_t time_extent_micros);
-
-  static void PrintTimelineJSON(JSONStream* stream,
-                                Profile::TagOrder tag_order,
-                                int64_t time_origin_micros,
-                                int64_t time_extent_micros,
-                                bool code_trie);
-
-  static void AddToTimeline(Profile::TagOrder tag_order,
-                            int64_t time_origin_micros,
-                            int64_t time_extent_micros,
-                            bool code_trie);
+                                        int64_t time_extent_micros,
+                                        bool include_code_samples);
 
   static void ClearSamples();
 
  private:
-  enum PrintKind {
-    kAsProfile,
-    kAsTimeline,
-    kAsPlatformTimeline,
-  };
-
   static void PrintJSONImpl(Thread* thread,
                             JSONStream* stream,
-                            Profile::TagOrder tag_order,
-                            intptr_t extra_tags,
                             SampleFilter* filter,
                             SampleBuffer* sample_buffer,
-                            PrintKind kind,
-                            bool code_trie);
+                            bool include_code_samples);
 };
 
 }  // namespace dart
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 497954e..21566b5 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -229,6 +229,192 @@
   }
 }
 
+class ProfileStackWalker {
+ public:
+  explicit ProfileStackWalker(Profile* profile, bool as_func = false)
+      : profile_(profile),
+        as_functions_(as_func),
+        index_(0),
+        sample_(profile->SampleAt(0)) {
+    ClearInliningData();
+  }
+
+  bool Down() {
+    if (as_functions_) {
+      return UpdateFunctionIndex();
+    } else {
+      ++index_;
+      return (index_ < sample_->length());
+    }
+  }
+
+  const char* CurrentName() {
+    if (as_functions_) {
+      ProfileFunction* func = GetFunction();
+      EXPECT(func != NULL);
+      return func->Name();
+    } else {
+      ProfileCode* code = GetCode();
+      EXPECT(code != NULL);
+      return code->name();
+    }
+  }
+
+  const char* CurrentToken() {
+    if (!as_functions_) {
+      return NULL;
+    }
+    ProfileFunction* func = GetFunction();
+    const Function& function = *(func->function());
+    if (function.IsNull()) {
+      // No function.
+      return NULL;
+    }
+    Zone* zone = Thread::Current()->zone();
+    const Script& script = Script::Handle(zone, function.script());
+    if (script.IsNull()) {
+      // No script.
+      return NULL;
+    }
+    ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
+    if (!func->GetSinglePosition(&pfsp)) {
+      // Not exactly one source position.
+      return NULL;
+    }
+    TokenPosition token_pos = pfsp.token_pos();
+    if (!token_pos.IsSourcePosition()) {
+      // Not a location in a script.
+      return NULL;
+    }
+    if (token_pos.IsSynthetic()) {
+      token_pos = token_pos.FromSynthetic();
+    }
+
+    String& str = String::Handle(zone);
+    if (script.kind() == RawScript::kKernelTag) {
+      intptr_t line = 0, column = 0, token_len = 0;
+      script.GetTokenLocation(token_pos, &line, &column, &token_len);
+      str = script.GetSnippet(line, column, line, column + token_len);
+    } else {
+      UNREACHABLE();
+    }
+    return str.IsNull() ? NULL : str.ToCString();
+  }
+
+  intptr_t CurrentInclusiveTicks() {
+    if (as_functions_) {
+      ProfileFunction* func = GetFunction();
+      EXPECT(func != NULL);
+      return func->inclusive_ticks();
+    } else {
+      ProfileCode* code = GetCode();
+      ASSERT(code != NULL);
+      return code->inclusive_ticks();
+    }
+  }
+
+  intptr_t CurrentExclusiveTicks() {
+    if (as_functions_) {
+      ProfileFunction* func = GetFunction();
+      EXPECT(func != NULL);
+      return func->exclusive_ticks();
+    } else {
+      ProfileCode* code = GetCode();
+      ASSERT(code != NULL);
+      return code->exclusive_ticks();
+    }
+  }
+
+  const char* VMTagName() { return VMTag::TagName(sample_->vm_tag()); }
+
+ private:
+  ProfileCode* GetCode() {
+    uword pc = sample_->At(index_);
+    int64_t timestamp = sample_->timestamp();
+    return profile_->GetCodeFromPC(pc, timestamp);
+  }
+
+  static const intptr_t kInvalidInlinedIndex = -1;
+
+  bool UpdateFunctionIndex() {
+    if (inlined_index_ != kInvalidInlinedIndex) {
+      if (inlined_index_ - 1 >= 0) {
+        --inlined_index_;
+        return true;
+      }
+      ClearInliningData();
+    }
+    ++index_;
+    return (index_ < sample_->length());
+  }
+
+  void ClearInliningData() {
+    inlined_index_ = kInvalidInlinedIndex;
+    inlined_functions_ = NULL;
+    inlined_token_positions_ = NULL;
+  }
+
+  ProfileFunction* GetFunction() {
+    // Check to see if we're currently processing inlined functions. If so,
+    // return the next inlined function.
+    ProfileFunction* function = GetInlinedFunction();
+    if (function != NULL) {
+      return function;
+    }
+
+    const uword pc = sample_->At(index_);
+    ProfileCode* profile_code =
+        profile_->GetCodeFromPC(pc, sample_->timestamp());
+    ASSERT(profile_code != NULL);
+    function = profile_code->function();
+    ASSERT(function != NULL);
+
+    TokenPosition token_position = TokenPosition::kNoSource;
+    Code& code = Code::ZoneHandle();
+    if (profile_code->code().IsCode()) {
+      code ^= profile_code->code().raw();
+      inlined_functions_cache_.Get(pc, code, sample_, index_,
+                                   &inlined_functions_,
+                                   &inlined_token_positions_, &token_position);
+    } else if (profile_code->code().IsBytecode()) {
+      // No inlining in bytecode.
+      const Bytecode& bc = Bytecode::CheckedHandle(Thread::Current()->zone(),
+                                                   profile_code->code().raw());
+      token_position = bc.GetTokenIndexOfPC(pc);
+    }
+
+    if (code.IsNull() || (inlined_functions_ == NULL) ||
+        (inlined_functions_->length() <= 1)) {
+      ClearInliningData();
+      // No inlined functions.
+      return function;
+    }
+
+    ASSERT(code.is_optimized());
+    inlined_index_ = inlined_functions_->length() - 1;
+    function = GetInlinedFunction();
+    ASSERT(function != NULL);
+    return function;
+  }
+
+  ProfileFunction* GetInlinedFunction() {
+    if ((inlined_index_ != kInvalidInlinedIndex) &&
+        (inlined_index_ < inlined_functions_->length())) {
+      return profile_->FindFunction(*(*inlined_functions_)[inlined_index_]);
+    }
+    return NULL;
+  }
+
+  Profile* profile_;
+  bool as_functions_;
+  intptr_t index_;
+  ProcessedSample* sample_;
+  ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
+  GrowableArray<const Function*>* inlined_functions_;
+  GrowableArray<TokenPosition>* inlined_token_positions_;
+  intptr_t inlined_index_;
+};
+
 ISOLATE_UNIT_TEST_CASE(Profiler_TrivialRecordAllocation) {
   EnableProfiler();
   DisableNativeProfileScope dnps;
@@ -269,17 +455,13 @@
     AllocationFilter filter(isolate->main_port(), class_a.id(),
                             before_allocations_micros,
                             allocation_extent_micros);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have 1 allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    // Exclusive code: B.boo -> main.
-    walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
       EXPECT(walker.Down());
@@ -293,56 +475,6 @@
       EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
       EXPECT(!walker.Down());
     }
-
-    // Inclusive code: main -> B.boo.
-    walker.Reset(Profile::kInclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    if (FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
-      EXPECT(walker.Down());
-    } else {
-      EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    if (!FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Inclusive function: main -> B.boo.
-    walker.Reset(Profile::kInclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    if (!FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
   }
 
   // Query with a time filter where no allocations occurred.
@@ -354,7 +486,7 @@
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id(),
                             Dart_TimelineGetMicros(), 16000);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples because none occured within
     // the specified time range.
     EXPECT_EQ(0, profile.sample_count());
@@ -404,129 +536,31 @@
     // Filter for the class in the time range.
     NativeAllocationSampleFilter filter(before_allocations_micros,
                                         allocation_extent_micros);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have 1 allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile)
 
-    // Exclusive code: NativeAllocationSampleHelper -> main.
-    walker.Reset(Profile::kExclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
+        // Move down from the root.
+        EXPECT(walker.Down());
     EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
                  walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(!walker.Down());
-
-    // Inclusive code: main -> NativeAllocationSampleHelper.
-    walker.Reset(Profile::kInclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
-                 walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
-    EXPECT(!walker.Down());
-
-    // Exclusive function: NativeAllocationSampleHelper -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
-                 walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(!walker.Down());
-
-    // Inclusive function: main -> NativeAllocationSampleHelper.
-    walker.Reset(Profile::kInclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
-                 walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
-    EXPECT(walker.Down());
-    EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-    EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
-    EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
+    EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
     EXPECT(!walker.Down());
   }
 
@@ -546,7 +580,7 @@
     // Filter for the class in the time range.
     NativeAllocationSampleFilter filter(before_allocations_micros,
                                         allocation_extent_micros);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have 0 allocation samples since we freed the memory.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -559,7 +593,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     NativeAllocationSampleFilter filter(Dart_TimelineGetMicros(), 16000);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples because none occured within
     // the specified time range.
     EXPECT_EQ(0, profile.sample_count());
@@ -606,7 +640,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -623,17 +657,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    // Exclusive code: B.boo -> main.
-    walker.Reset(Profile::kExclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
       EXPECT(walker.Down());
@@ -647,56 +676,6 @@
       EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
       EXPECT(!walker.Down());
     }
-
-    // Inclusive code: main -> B.boo.
-    walker.Reset(Profile::kInclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    if (FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
-      EXPECT(walker.Down());
-    } else {
-      EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Exclusive function: boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    if (!FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Inclusive function: main -> boo.
-    walker.Reset(Profile::kInclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    if (!FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
   }
 
   // Turn off allocation tracing for A.
@@ -711,7 +690,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -749,7 +728,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -769,24 +748,18 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have three allocation samples.
     EXPECT_EQ(3, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    // Exclusive code: B.boo -> main.
-    walker.Reset(Profile::kExclusiveCode);
     // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
       EXPECT_EQ(3, walker.CurrentInclusiveTicks());
       EXPECT(walker.Down());
       EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
       EXPECT_EQ(3, walker.CurrentInclusiveTicks());
       EXPECT_EQ(0, walker.CurrentExclusiveTicks());
       EXPECT(!walker.Down());
@@ -795,49 +768,15 @@
       EXPECT_EQ(3, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
       EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
       EXPECT_EQ(3, walker.CurrentInclusiveTicks());
       EXPECT(walker.Down());
       EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
       EXPECT_EQ(3, walker.CurrentInclusiveTicks());
       EXPECT_EQ(0, walker.CurrentExclusiveTicks());
       EXPECT(!walker.Down());
     }
-
-    // Inclusive code: main -> B.boo.
-    walker.Reset(Profile::kInclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    if (FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
-      EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
-      EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-      EXPECT(walker.Down());
-    } else {
-      EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
-      EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentNodeTickCount());
-      EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-      EXPECT(walker.Down());
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentExclusiveTicks());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
   }
 }
-
 ISOLATE_UNIT_TEST_CASE(Profiler_FunctionTicks) {
   EnableProfiler();
   DisableNativeProfileScope dnps;
@@ -870,7 +809,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -890,52 +829,25 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have three allocation samples.
     EXPECT_EQ(3, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
       EXPECT_EQ(3, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
     }
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(3, walker.CurrentNodeTickCount());
     EXPECT_EQ(3, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT(!walker.Down());
-
-    // Inclusive function: main -> B.boo.
-    walker.Reset(Profile::kInclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(3, walker.CurrentNodeTickCount());
-    EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(3, walker.CurrentNodeTickCount());
-    EXPECT_EQ(3, walker.CurrentInclusiveTicks());
-    EXPECT(walker.Down());
-    if (!FLAG_enable_interpreter) {
-      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-      EXPECT_EQ(3, walker.CurrentExclusiveTicks());
-      EXPECT(walker.Down());
-    }
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
   }
 }
 
@@ -965,7 +877,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), double_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -978,21 +890,17 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), double_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
     if (FLAG_enable_interpreter) {
-      EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-      EXPECT(walker.Down());
+      EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
       EXPECT_STREQ("[Bytecode] foo", walker.CurrentName());
       EXPECT(!walker.Down());
     } else {
-      EXPECT_STREQ("Double_add", walker.CurrentName());
-      EXPECT(walker.Down());
+      EXPECT_STREQ("Double_add", walker.VMTagName());
       EXPECT_STREQ("[Unoptimized] double._add", walker.CurrentName());
       EXPECT(walker.Down());
       EXPECT_STREQ("[Unoptimized] double.+", walker.CurrentName());
@@ -1010,7 +918,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), double_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1037,7 +945,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), array_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1050,15 +958,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), array_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateArray", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] new _List", walker.CurrentName());
       EXPECT(walker.Down());
@@ -1082,7 +987,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), array_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1104,7 +1009,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), array_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples, since empty
     // growable lists use a shared backing.
     EXPECT_EQ(0, profile.sample_count());
@@ -1134,7 +1039,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), context_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1147,15 +1052,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), context_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateContext", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateContext", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] foo", walker.CurrentName());
       EXPECT(!walker.Down());
@@ -1175,7 +1077,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), context_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1216,15 +1118,12 @@
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), closure_class.id());
     filter.set_enable_vm_ticks(true);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_SUBSTRING("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_SUBSTRING("DRT_AllocateObject", walker.VMTagName());
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate _Closure", walker.CurrentName());
       EXPECT(walker.Down());
@@ -1245,7 +1144,7 @@
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), closure_class.id());
     filter.set_enable_vm_ticks(true);
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1275,7 +1174,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), float32_list_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1288,15 +1187,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), float32_list_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("TypedData_Float32Array_new", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("TypedData_Float32Array_new", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] new Float32List", walker.CurrentName());
       EXPECT(walker.Down());
@@ -1318,7 +1214,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), float32_list_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1331,7 +1227,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), float32_list_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should now have two allocation samples.
     EXPECT_EQ(2, profile.sample_count());
   }
@@ -1363,7 +1259,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1376,15 +1272,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("String_concat", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("String_concat", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] _StringBase.+", walker.CurrentName());
       EXPECT(walker.Down());
@@ -1406,7 +1299,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1419,7 +1312,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should now have two allocation samples.
     EXPECT_EQ(2, profile.sample_count());
   }
@@ -1451,7 +1344,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1464,15 +1357,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("OneByteString_allocate", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("OneByteString_allocate", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] _OneByteString._allocate", walker.CurrentName());
       EXPECT(walker.Down());
@@ -1504,7 +1394,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should still only have one allocation sample.
     EXPECT_EQ(1, profile.sample_count());
   }
@@ -1517,7 +1407,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should now have two allocation samples.
     EXPECT_EQ(2, profile.sample_count());
   }
@@ -1574,7 +1464,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1592,215 +1482,48 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have 50,000 allocation samples.
     EXPECT_EQ(50000, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
-    // We have two code objects: mainA and B.boo.
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(!walker.Down());
-    // We have two code objects: mainA and B.boo.
-    walker.Reset(Profile::kInclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Inline expansion should show us the complete call chain:
-    // mainA -> B.boo -> B.foo -> B.choo.
-    walker.Reset(Profile::kExclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.choo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.foo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("mainA", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(!walker.Down());
-
-    // Inline expansion should show us the complete call chain:
-    // mainA -> B.boo -> B.foo -> B.choo.
-    walker.Reset(Profile::kInclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("mainA", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.foo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT_EQ(0, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.choo", walker.CurrentName());
-    EXPECT_EQ(1, walker.SiblingCount());
-    EXPECT_EQ(50000, walker.CurrentNodeTickCount());
-    EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
-  }
-
-  // Test code transition tags.
-  {
-    Thread* thread = Thread::Current();
-    Isolate* isolate = thread->isolate();
-    StackZone zone(thread);
-    HANDLESCOPE(thread);
-    Profile profile(isolate);
-    AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags,
-                  ProfilerService::kCodeTransitionTagsBit);
-    // We should have 50,000 allocation samples.
-    EXPECT_EQ(50000, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
-    // We have two code objects: mainA and B.boo.
-    walker.Reset(Profile::kExclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(!walker.Down());
-    // We have two code objects: mainA and B.boo.
-    walker.Reset(Profile::kInclusiveCode);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Inline expansion should show us the complete call chain:
-    // mainA -> B.boo -> B.foo -> B.choo.
-    walker.Reset(Profile::kExclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Inline End]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.choo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.foo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Inline Start]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("mainA", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(!walker.Down());
-
-    // Inline expansion should show us the complete call chain:
-    // mainA -> B.boo -> B.foo -> B.choo.
-    walker.Reset(Profile::kInclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("mainA", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Inline Start]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.foo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("B.choo", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Inline End]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
+    {
+      ProfileStackWalker walker(&profile);
+      // We have two code objects: mainA and B.boo.
+      EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+      EXPECT(!walker.Down());
+    }
+    {
+      ProfileStackWalker walker(&profile, true);
+      // Inline expansion should show us the complete call chain:
+      // mainA -> B.boo -> B.foo -> B.choo.
+      EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+      EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("B.choo", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("B.foo", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("B.boo", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+      EXPECT(walker.Down());
+      EXPECT_STREQ("mainA", walker.CurrentName());
+      EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+      EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+      EXPECT(!walker.Down());
+    }
   }
 }
 
@@ -1881,7 +1604,7 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have no allocation samples.
     EXPECT_EQ(0, profile.sample_count());
   }
@@ -1898,15 +1621,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
     // Inline expansion should show us the complete call chain:
-    walker.Reset(Profile::kExclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("maybeAlloc", walker.CurrentName());
@@ -1916,22 +1636,6 @@
     EXPECT_STREQ("a", walker.CurrentName());
     EXPECT(walker.Down());
     EXPECT_STREQ("mainAlloc", walker.CurrentName());
-
-    // Inline expansion should show us the complete call chain:
-    walker.Reset(Profile::kInclusiveFunction);
-    EXPECT(walker.Down());
-    EXPECT_STREQ("mainAlloc", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("a", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("right", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("maybeAlloc", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(!walker.Down());
   }
 }
 
@@ -1989,16 +1693,12 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have 1 allocation sample.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile);
 
-    walker.Reset(Profile::kExclusiveCode);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (FLAG_enable_interpreter) {
       EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
       EXPECT(walker.Down());
@@ -2127,29 +1827,22 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
       EXPECT_EQ(1, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
     }
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
@@ -2215,27 +1908,21 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
     // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentExclusiveTicks());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
@@ -2295,47 +1982,37 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
       EXPECT_EQ(1, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
     }
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.oats", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.fox", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("oats", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.bacon", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("fox", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2414,45 +2091,35 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
     EXPECT_EQ(1, walker.CurrentExclusiveTicks());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.oats", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.fox", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("oats", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.bacon", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("fox", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2515,53 +2182,42 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
       EXPECT_EQ(1, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
     }
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.oats", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.fox", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("oats", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.+", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("fox", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.bacon", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("+", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2643,53 +2299,42 @@
     HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate->main_port(), class_a.id());
-    profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+    profile.Build(thread, &filter, Profiler::sample_buffer());
     // We should have one allocation samples.
     EXPECT_EQ(1, profile.sample_count());
-    ProfileTrieWalker walker(&profile);
+    ProfileStackWalker walker(&profile, true);
 
-    // Exclusive function: B.boo -> main.
-    walker.Reset(Profile::kExclusiveFunction);
-    // Move down from the root.
-    EXPECT(walker.Down());
-    EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
-    EXPECT(walker.Down());
+    EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
     if (!FLAG_enable_interpreter) {
       EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
       EXPECT_EQ(1, walker.CurrentExclusiveTicks());
       EXPECT(walker.Down());
     }
     EXPECT_STREQ("B.boo", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_STREQ("A", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("B.oats", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("boo", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.fox", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("oats", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.+", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("fox", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("C.bacon", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("+", walker.CurrentToken());
     EXPECT(walker.Down());
     EXPECT_STREQ("main", walker.CurrentName());
-    EXPECT_EQ(1, walker.CurrentNodeTickCount());
     EXPECT_EQ(1, walker.CurrentInclusiveTicks());
     EXPECT_EQ(0, walker.CurrentExclusiveTicks());
     EXPECT_STREQ("bacon", walker.CurrentToken());
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index d937e14..1f2ccdb 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -637,4 +637,29 @@
 }
 END_LEAF_RUNTIME_ENTRY
 
+const char* RawPcDescriptors::KindToCString(Kind k) {
+  switch (k) {
+#define ENUM_CASE(name, init)                                                  \
+  case Kind::k##name:                                                          \
+    return #name;
+    FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+      return nullptr;
+  }
+}
+
+bool RawPcDescriptors::KindFromCString(const char* cstr, Kind* out) {
+  ASSERT(cstr != nullptr && out != nullptr);
+#define ENUM_CASE(name, init)                                                  \
+  if (strcmp(#name, cstr) == 0) {                                              \
+    *out = Kind::k##name;                                                      \
+    return true;                                                               \
+  }
+  FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_CASE)
+#undef ENUM_CASE
+  return false;
+}
+#undef PREFIXED_NAME
+
 }  // namespace dart
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 7d9126c..fc8dfc7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -65,6 +65,7 @@
 enum class MemoryOrder {
   kRelaxed,
   kRelease,
+  kAcquire,
 };
 
 #define SNAPSHOT_WRITER_SUPPORT()                                              \
@@ -689,7 +690,7 @@
   friend class RawInstance;
   friend class Scavenger;
   friend class ScavengerVisitor;
-  friend class ImageReader;                // tags_ check
+  friend class ImageReader;  // tags_ check
   friend class ImageWriter;
   friend class AssemblyImageWriter;
   friend class BlobImageWriter;
@@ -716,9 +717,9 @@
 class RawClass : public RawObject {
  public:
   enum ClassFinalizedState {
-    kAllocated = 0,         // Initial state.
-    kPreFinalized,          // VM classes: size precomputed, but no checks done.
-    kFinalized,             // Class parsed, finalized and ready for use.
+    kAllocated = 0,  // Initial state.
+    kPreFinalized,   // VM classes: size precomputed, but no checks done.
+    kFinalized,      // Class parsed, finalized and ready for use.
   };
   enum ClassLoadingState {
     // Class object is created, but it is not filled up.
@@ -750,13 +751,13 @@
   RawTypeArguments* type_parameters_;  // Array of TypeParameter.
   RawAbstractType* super_type_;
   RawFunction* signature_function_;  // Associated function for typedef class.
-  RawArray* constants_;      // Canonicalized const instances of this class.
-  RawType* declaration_type_;              // Declaration type for this class.
+  RawArray* constants_;        // Canonicalized const instances of this class.
+  RawType* declaration_type_;  // Declaration type for this class.
   RawArray* invocation_dispatcher_cache_;  // Cache for dispatcher functions.
   RawCode* allocation_stub_;  // Stub code for allocation of instances.
   RawGrowableObjectArray* direct_implementors_;  // Array of Class.
-  RawGrowableObjectArray* direct_subclasses_;  // Array of Class.
-  RawArray* dependent_code_;                   // CHA optimized codes.
+  RawGrowableObjectArray* direct_subclasses_;    // Array of Class.
+  RawArray* dependent_code_;                     // CHA optimized codes.
   VISIT_TO(RawObject*, dependent_code_);
   RawObject** to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
@@ -837,33 +838,78 @@
 
 class RawFunction : public RawObject {
  public:
+  // When you add a new kind, please also update the observatory to account
+  // for the new string returned by KindToCString().
+  // - runtime/observatory/lib/src/models/objects/function.dart (FunctionKind)
+  // - runtime/observatory/lib/src/elements/function_view.dart
+  //   (_functionKindToString)
+  // - runtime/observatory/lib/src/service/object.dart (stringToFunctionKind)
+#define FOR_EACH_RAW_FUNCTION_KIND(V)                                          \
+  /* an ordinary or operator method */                                         \
+  V(RegularFunction)                                                           \
+  /* a user-declared closure function */                                       \
+  V(ClosureFunction)                                                           \
+  /* an implicit closure (i.e., tear-off) */                                   \
+  V(ImplicitClosureFunction)                                                   \
+  /* a signature only without actual code */                                   \
+  V(SignatureFunction)                                                         \
+  /* getter functions e.g: get foo() { .. } */                                 \
+  V(GetterFunction)                                                            \
+  /* setter functions e.g: set foo(..) { .. } */                               \
+  V(SetterFunction)                                                            \
+  /* a generative (is_static=false) or factory (is_static=true) constructor */ \
+  V(Constructor)                                                               \
+  /* an implicit getter for instance fields */                                 \
+  V(ImplicitGetter)                                                            \
+  /* an implicit setter for instance fields */                                 \
+  V(ImplicitSetter)                                                            \
+  /* represents an implicit getter for static fields with initializers */      \
+  V(ImplicitStaticGetter)                                                      \
+  /* the initialization expression for a static or instance field */           \
+  V(FieldInitializer)                                                          \
+  /* return a closure on the receiver for tear-offs */                         \
+  V(MethodExtractor)                                                           \
+  /* builds an Invocation and invokes noSuchMethod */                          \
+  V(NoSuchMethodDispatcher)                                                    \
+  /* invokes a field as a closure (i.e., call-through-getter) */               \
+  V(InvokeFieldDispatcher)                                                     \
+  /* a generated irregexp matcher function. */                                 \
+  V(IrregexpFunction)                                                          \
+  /* a forwarder which performs type checks for arguments of a dynamic call */ \
+  /* (i.e., those checks omitted by the caller for interface calls). */        \
+  V(DynamicInvocationForwarder)                                                \
+  V(FfiTrampoline)
+
   enum Kind {
-    kRegularFunction,          // an ordinary or operator method
-    kClosureFunction,          // a user-declared closure function
-    kImplicitClosureFunction,  // an implicit closure (i.e., tear-off)
-    kSignatureFunction,        // a signature only without actual code
-    kGetterFunction,           // getter functions e.g: get foo() { .. }
-    kSetterFunction,           // setter functions e.g: set foo(..) { .. }
-    kConstructor,              // a generative (is_static=false) or
-                               // factory (is_static=true) constructor
-    kImplicitGetter,           // an implicit getter for instance fields
-    kImplicitSetter,           // an implicit setter for instance fields
-    kImplicitStaticGetter,     // represents an implicit getter for static
-                               // fields with initializers
-    kFieldInitializer,         // the initialization expression for a static
-                               // or instance field
-    kMethodExtractor,          // return a closure on the receiver for tear-offs
-    kNoSuchMethodDispatcher,   // builds an Invocation and invokes noSuchMethod
-    kInvokeFieldDispatcher,    // invokes a field as a closure (i.e.,
-                               // call-through-getter)
-    kIrregexpFunction,         // a generated irregexp matcher function.
-    kDynamicInvocationForwarder,  // a forwarder which performs type checks for
-                                  // arguments of a dynamic call (i.e., those
-                                  // checks omitted by the caller for interface
-                                  // calls).
-    kFfiTrampoline,
+#define KIND_DEFN(Name) k##Name,
+    FOR_EACH_RAW_FUNCTION_KIND(KIND_DEFN)
+#undef KIND_DEFN
   };
 
+  static const char* KindToCString(Kind k) {
+    switch (k) {
+#define KIND_CASE(Name)                                                        \
+  case Kind::k##Name:                                                          \
+    return #Name;
+      FOR_EACH_RAW_FUNCTION_KIND(KIND_CASE)
+#undef KIND_CASE
+      default:
+        UNREACHABLE();
+        return nullptr;
+    }
+  }
+
+  static bool KindFromCString(const char* str, Kind* out) {
+#define KIND_CASE(Name)                                                        \
+  if (strcmp(str, #Name) == 0) {                                               \
+    *out = Kind::k##Name;                                                      \
+    return true;                                                               \
+  }
+    FOR_EACH_RAW_FUNCTION_KIND(KIND_CASE)
+#undef KIND_CASE
+    return false;
+  }
+
   enum AsyncModifier {
     kNoModifier = 0x0,
     kAsyncBit = 0x1,
@@ -881,7 +927,7 @@
 
   RAW_HEAP_OBJECT_IMPLEMENTATION(Function);
 
-  uword entry_point_;  // Accessed from generated code.
+  uword entry_point_;            // Accessed from generated code.
   uword unchecked_entry_point_;  // Accessed from generated code.
 
   VISIT_FROM(RawObject*, name_);
@@ -924,11 +970,10 @@
 
   NOT_IN_PRECOMPILED(TokenPosition token_pos_);
   NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
-  uint32_t kind_tag_;                          // See Function::KindTagBits.
+  uint32_t kind_tag_;  // See Function::KindTagBits.
   uint32_t packed_fields_;
 
-  typedef BitField<uint32_t, bool, 0, 1>
-      PackedHasNamedOptionalParameters;
+  typedef BitField<uint32_t, bool, 0, 1> PackedHasNamedOptionalParameters;
   typedef BitField<uint32_t,
                    bool,
                    PackedHasNamedOptionalParameters::kNextBit,
@@ -1160,7 +1205,6 @@
     kLoadRequested,   // Compiler or script requested load of library.
     kLoadInProgress,  // Library is in the process of being loaded.
     kLoaded,          // Library is loaded.
-    kLoadError,       // Error occurred during load of the Library.
   };
 
   RAW_HEAP_OBJECT_IMPLEMENTATION(Library);
@@ -1175,12 +1219,11 @@
   RawGrowableObjectArray* owned_scripts_;
   RawArray* imports_;        // List of Namespaces imported without prefix.
   RawArray* exports_;        // List of re-exported Namespaces.
-  RawInstance* load_error_;  // Error iff load_state_ == kLoadError.
   RawExternalTypedData* kernel_data_;
   RawObject** to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
       case Snapshot::kFullAOT:
-        return reinterpret_cast<RawObject**>(&ptr()->load_error_);
+        return reinterpret_cast<RawObject**>(&ptr()->exports_);
       case Snapshot::kFull:
       case Snapshot::kFullJIT:
         return reinterpret_cast<RawObject**>(&ptr()->kernel_data_);
@@ -1258,7 +1301,7 @@
 class RawCode : public RawObject {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
 
-  uword entry_point_;          // Accessed from generated code.
+  uword entry_point_;  // Accessed from generated code.
 
   // In AOT this entry-point supports switchable calls. It checks the type of
   // the receiver on entry to the function and calls a stub to patch up the
@@ -1294,7 +1337,7 @@
   // type checks are necessary or this Code belongs to a stub). In this case
   // 'unchecked_entry_point_' will refer to the same position as 'entry_point_'.
   //
-  uword unchecked_entry_point_;  // Accessed from generated code.
+  uword unchecked_entry_point_;              // Accessed from generated code.
   uword monomorphic_unchecked_entry_point_;  // Accessed from generated code.
 
   VISIT_FROM(RawObject*, object_pool_);
@@ -1374,11 +1417,13 @@
   VISIT_TO(RawObject*, var_descriptors_);
 #endif
 
-  RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
+  RawObject** to_snapshot(Snapshot::Kind kind) {
+    return reinterpret_cast<RawObject**>(&ptr()->pc_descriptors_);
+  }
 
   int32_t instructions_binary_offset_;
   int32_t source_positions_binary_offset_;
-  NOT_IN_PRODUCT(int32_t local_variables_binary_offset_);
+  int32_t local_variables_binary_offset_;
 
   static bool ContainsPC(RawObject* raw_obj, uword pc);
 
@@ -1451,18 +1496,39 @@
 
 class RawPcDescriptors : public RawObject {
  public:
+// The macro argument V is passed two arguments, the raw name of the enum value
+// and the initialization expression used within the enum definition.  The uses
+// of enum values inside the initialization expression are hardcoded currently,
+// so the second argument is useless outside the enum definition and should be
+// dropped by other users of this macro.
+#define FOR_EACH_RAW_PC_DESCRIPTOR(V)                                          \
+  /* Deoptimization continuation point. */                                     \
+  V(Deopt, 1)                                                                  \
+  /* IC call. */                                                               \
+  V(IcCall, kDeopt << 1)                                                       \
+  /* Call to a known target via stub. */                                       \
+  V(UnoptStaticCall, kIcCall << 1)                                             \
+  /* Runtime call. */                                                          \
+  V(RuntimeCall, kUnoptStaticCall << 1)                                        \
+  /* OSR entry point in unopt. code. */                                        \
+  V(OsrEntry, kRuntimeCall << 1)                                               \
+  /* Call rewind target address. */                                            \
+  V(Rewind, kOsrEntry << 1)                                                    \
+  /* Target-word-size relocation. */                                           \
+  V(BSSRelocation, kRewind << 1)                                               \
+  V(Other, kBSSRelocation << 1)                                                \
+  V(AnyKind, -1)
+
   enum Kind {
-    kDeopt = 1,                            // Deoptimization continuation point.
-    kIcCall = kDeopt << 1,                 // IC call.
-    kUnoptStaticCall = kIcCall << 1,       // Call to a known target via stub.
-    kRuntimeCall = kUnoptStaticCall << 1,  // Runtime call.
-    kOsrEntry = kRuntimeCall << 1,         // OSR entry point in unopt. code.
-    kRewind = kOsrEntry << 1,              // Call rewind target address.
-    kOther = kRewind << 1,
-    kLastKind = kOther,
-    kAnyKind = -1
+#define ENUM_DEF(name, init) k##name = init,
+    FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_DEF)
+#undef ENUM_DEF
+        kLastKind = kOther,
   };
 
+  static const char* KindToCString(Kind k);
+  static bool KindFromCString(const char* cstr, Kind* out);
+
   class MergedKindTry {
    public:
     // Most of the time try_index will be small and merged field will fit into
@@ -1850,9 +1916,7 @@
   RawString* name_;           // Library prefix name.
   RawLibrary* importer_;      // Library which declares this prefix.
   RawArray* imports_;         // Libraries imported with this prefix.
-  RawArray* dependent_code_;  // Code that refers to deferred, unloaded
-                              // library prefix.
-  VISIT_TO(RawObject*, dependent_code_)
+  VISIT_TO(RawObject*, imports_)
   RawObject** to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
       case Snapshot::kFull:
@@ -1870,7 +1934,6 @@
   }
   uint16_t num_imports_;  // Number of library entries in libraries_.
   bool is_deferred_load_;
-  bool is_loaded_;
 };
 
 class RawTypeArguments : public RawInstance {
@@ -2077,10 +2140,6 @@
 
  private:
   friend class Library;
-  friend class OneByteStringSerializationCluster;
-  friend class TwoByteStringSerializationCluster;
-  friend class OneByteStringDeserializationCluster;
-  friend class TwoByteStringDeserializationCluster;
   friend class RODataSerializationCluster;
   friend class ImageWriter;
 };
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index f90a01d..3dc239b 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -73,7 +73,6 @@
   F(Library, owned_scripts_)                                                   \
   F(Library, imports_)                                                         \
   F(Library, exports_)                                                         \
-  F(Library, load_error_)                                                      \
   F(Library, kernel_data_)                                                     \
   F(Library, resolved_names_)                                                  \
   F(Library, exported_names_)                                                  \
@@ -138,7 +137,6 @@
   F(LibraryPrefix, name_)                                                      \
   F(LibraryPrefix, importer_)                                                  \
   F(LibraryPrefix, imports_)                                                   \
-  F(LibraryPrefix, dependent_code_)                                            \
   F(TypeArguments, instantiations_)                                            \
   F(TypeArguments, length_)                                                    \
   F(TypeArguments, hash_)                                                      \
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 22a7016..6773141 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1311,6 +1311,7 @@
   intptr_t length_in_bytes = len * element_size;
   NoSafepointScope no_safepoint;
   uint8_t* data = reinterpret_cast<uint8_t*>(result.DataAddr(0));
+  reader->Align(Zone::kAlignment);
   reader->ReadBytes(data, length_in_bytes);
 
   // If it is a canonical constant make it one.
@@ -1456,6 +1457,7 @@
     writer->WriteTags(writer->GetObjectTags(this));
     writer->Write<RawObject*>(ptr()->length_);
     uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
+    writer->Align(Zone::kAlignment);
     writer->WriteBytes(data, bytes);
   }
 }
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 12796de..23efd9d 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -3556,7 +3556,7 @@
 
 void DotPrinter::PrintNode(const char* label, RegExpNode* node) {
   OS::PrintErr("digraph G {\n  graph [label=\"");
-  for (intptr_t i = 0; label[i]; i++) {
+  for (intptr_t i = 0; label[i] != '\0'; i++) {
     switch (label[i]) {
       case '\\':
         OS::PrintErr("\\\\");
@@ -5286,7 +5286,7 @@
 
   const Function& function = parsed_function->function();
   const intptr_t specialization_cid = function.string_specialization_cid();
-  const intptr_t is_sticky = function.is_sticky_specialization();
+  const bool is_sticky = function.is_sticky_specialization();
   const bool is_one_byte = (specialization_cid == kOneByteStringCid ||
                             specialization_cid == kExternalOneByteStringCid);
   RegExp& regexp = RegExp::Handle(zone, function.regexp());
diff --git a/runtime/vm/regexp_ast.h b/runtime/vm/regexp_ast.h
index 4fb64a3..6301d4d 100644
--- a/runtime/vm/regexp_ast.h
+++ b/runtime/vm/regexp_ast.h
@@ -204,10 +204,10 @@
   // * : All characters
   uint16_t standard_type() const { return set_.standard_set_type(); }
   ZoneGrowableArray<CharacterRange>* ranges() { return set_.ranges(); }
-  bool is_negated() const { return character_class_flags_ & NEGATED; }
+  bool is_negated() const { return (character_class_flags_ & NEGATED) != 0; }
   RegExpFlags flags() const { return flags_; }
   bool contains_split_surrogate() const {
-    return character_class_flags_ & CONTAINS_SPLIT_SURROGATE;
+    return (character_class_flags_ & CONTAINS_SPLIT_SURROGATE) != 0;
   }
 
  private:
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index 40bf227..3f3bdf3 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -1506,7 +1506,7 @@
   UErrorCode ec = U_ZERO_ERROR;
   icu::UnicodeSet set;
   set.applyIntPropertyValue(property, property_value, ec);
-  bool success = ec == U_ZERO_ERROR && !set.isEmpty();
+  bool success = ec == U_ZERO_ERROR && (set.isEmpty() == 0);
 
   if (success) {
     set.removeAllStrings();
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 1049692..3641e8a 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1131,7 +1131,7 @@
   if (Debugger::IsDebugging(thread, caller_function)) return;
 #endif
 
-  intptr_t num_checks = ic_data.NumberOfChecks();
+  const intptr_t num_checks = ic_data.NumberOfChecks();
 
   // Monomorphic call.
   if (FLAG_unopt_monomorphic_calls && (num_checks == 1)) {
@@ -1168,7 +1168,7 @@
     const Array& descriptor =
         Array::Handle(zone, ic_data.arguments_descriptor());
     const MegamorphicCache& cache = MegamorphicCache::Handle(
-        zone, MegamorphicCacheTable::LookupOriginal(thread, name, descriptor));
+        zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
     ic_data.set_is_megamorphic(true);
     CodePatcher::PatchInstanceCallAt(caller_frame->pc(), caller_code, cache,
                                      StubCode::MegamorphicCall());
@@ -1795,8 +1795,7 @@
       if (number_of_checks > FLAG_max_polymorphic_checks) {
         // Switch to megamorphic call.
         const MegamorphicCache& cache = MegamorphicCache::Handle(
-            zone,
-            MegamorphicCacheTable::LookupOriginal(thread, name, descriptor));
+            zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
         DartFrameIterator iterator(thread,
                                    StackFrameIterator::kNoCrossThreadIteration);
         StackFrame* miss_function_frame = iterator.NextFrame();
@@ -2054,12 +2053,12 @@
       }
     }
   }
-  if ((FLAG_deoptimize_filter != NULL) || (FLAG_stacktrace_filter != NULL) ||
-      FLAG_reload_every) {
+  if (FLAG_deoptimize_filter != nullptr || FLAG_stacktrace_filter != nullptr ||
+      (FLAG_reload_every != 0)) {
     DartFrameIterator iterator(thread,
                                StackFrameIterator::kNoCrossThreadIteration);
     StackFrame* frame = iterator.NextFrame();
-    ASSERT(frame != NULL);
+    ASSERT(frame != nullptr);
     Code& code = Code::Handle();
     Function& function = Function::Handle();
     if (frame->is_interpreted()) {
@@ -2071,21 +2070,22 @@
     }
     ASSERT(!function.IsNull());
     const char* function_name = function.ToFullyQualifiedCString();
-    ASSERT(function_name != NULL);
+    ASSERT(function_name != nullptr);
     if (!code.IsNull()) {
       if (!code.is_optimized() && FLAG_reload_every_optimized) {
         // Don't do the reload if we aren't inside optimized code.
         do_reload = false;
       }
-      if (code.is_optimized() && FLAG_deoptimize_filter != NULL &&
-          strstr(function_name, FLAG_deoptimize_filter) != NULL) {
+      if (code.is_optimized() && FLAG_deoptimize_filter != nullptr &&
+          strstr(function_name, FLAG_deoptimize_filter) != nullptr &&
+          !function.ForceOptimize()) {
         OS::PrintErr("*** Forcing deoptimization (%s)\n",
                      function.ToFullyQualifiedCString());
         do_deopt = true;
       }
     }
-    if (FLAG_stacktrace_filter != NULL &&
-        strstr(function_name, FLAG_stacktrace_filter) != NULL) {
+    if (FLAG_stacktrace_filter != nullptr &&
+        strstr(function_name, FLAG_stacktrace_filter) != nullptr) {
       OS::PrintErr("*** Computing stacktrace (%s)\n",
                    function.ToFullyQualifiedCString());
       do_stacktrace = true;
@@ -2149,15 +2149,18 @@
     intptr_t num_frames = stack->Length();
     for (intptr_t i = 0; i < num_frames; i++) {
       ActivationFrame* frame = stack->FrameAt(i);
-#ifndef DART_PRECOMPILED_RUNTIME
-      if (!frame->IsInterpreted() && !frame->function().ForceOptimize()) {
-        // Ensure that we have unoptimized code.
-        frame->function().EnsureHasCompiledUnoptimizedCode();
-      }
-      const int num_vars = frame->NumLocalVariables();
-#else
+      int num_vars = 0;
       // Variable locations and number are unknown when precompiling.
-      const int num_vars = 0;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+      // NumLocalVariables() can call EnsureHasUnoptimizedCode() for
+      // non-interpreted functions.
+      if (!frame->function().ForceOptimize()) {
+        if (!frame->IsInterpreted()) {
+          // Ensure that we have unoptimized code.
+          frame->function().EnsureHasCompiledUnoptimizedCode();
+        }
+        num_vars = frame->NumLocalVariables();
+      }
 #endif
       TokenPosition unused = TokenPosition::kNoSource;
       for (intptr_t v = 0; v < num_vars; v++) {
@@ -2750,11 +2753,11 @@
     THR_Print("== Deoptimizing code for '%s', %s, %s\n",
               function.ToFullyQualifiedCString(),
               deoptimizing_code ? "code & frame" : "frame",
-              is_lazy_deopt ? "lazy-deopt" : "");
+              (is_lazy_deopt != 0u) ? "lazy-deopt" : "");
   }
 
 #if !defined(TARGET_ARCH_DBC)
-  if (is_lazy_deopt) {
+  if (is_lazy_deopt != 0u) {
     uword deopt_pc = isolate->FindPendingDeopt(caller_frame->fp());
     if (FLAG_trace_deoptimization) {
       THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n", caller_frame->fp(),
diff --git a/runtime/vm/scope_timer.h b/runtime/vm/scope_timer.h
index c910e34..0707980 100644
--- a/runtime/vm/scope_timer.h
+++ b/runtime/vm/scope_timer.h
@@ -5,8 +5,11 @@
 #ifndef RUNTIME_VM_SCOPE_TIMER_H_
 #define RUNTIME_VM_SCOPE_TIMER_H_
 
+#include "platform/allocation.h"
 #include "platform/globals.h"
 
+#include "vm/os.h"
+
 namespace dart {
 
 // Simple utility class for timing a block of code.
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index 71ef849..69e8510 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -60,7 +60,7 @@
 
   explicit VariableIndex(int value = kInvalidIndex) : value_(value) {}
 
-  int operator==(const VariableIndex& other) { return value_ == other.value_; }
+  bool operator==(const VariableIndex& other) { return value_ == other.value_; }
 
   bool IsValid() const { return value_ != kInvalidIndex; }
 
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index d212875..4ab9c57 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -146,7 +146,7 @@
       return true;
     }
   }
-  if (stream_listen_callback_) {
+  if (stream_listen_callback_ != nullptr) {
     Thread* T = Thread::Current();
     TransitionVMToNative transition(T);
     return (*stream_listen_callback_)(stream_id);
@@ -165,7 +165,7 @@
       return;
     }
   }
-  if (stream_cancel_callback_) {
+  if (stream_cancel_callback_ != nullptr) {
     Thread* T = Thread::Current();
     TransitionVMToNative transition(T);
     return (*stream_cancel_callback_)(stream_id);
@@ -2041,7 +2041,7 @@
     Breakpoint* bpt = NULL;
     if (GetIntegerId(rest, &bpt_id)) {
       bpt = isolate->debugger()->GetBreakpointById(bpt_id);
-      if (bpt) {
+      if (bpt != nullptr) {
         *result = ObjectIdRing::kValid;
         return bpt;
       }
@@ -3828,100 +3828,30 @@
   return true;
 }
 
-static const char* const tags_enum_names[] = {
-    "None", "UserVM", "UserOnly", "VMUser", "VMOnly", NULL,
-};
-
-static const Profile::TagOrder tags_enum_values[] = {
-    Profile::kNoTags, Profile::kUserVM, Profile::kUser,
-    Profile::kVMUser, Profile::kVM,
-    Profile::kNoTags,  // Default value.
-};
-
-static const MethodParameter* get_cpu_profile_params[] = {
+static const MethodParameter* get_cpu_samples_params[] = {
     RUNNABLE_ISOLATE_PARAMETER,
-    new EnumParameter("tags", true, tags_enum_names),
-    new BoolParameter("_codeTransitionTags", false),
     new Int64Parameter("timeOriginMicros", false),
     new Int64Parameter("timeExtentMicros", false),
     NULL,
 };
 
-// TODO(johnmccutchan): Rename this to GetCpuSamples.
-static bool GetCpuProfile(Thread* thread, JSONStream* js) {
-  if (CheckProfilerDisabled(thread, js)) {
-    return true;
-  }
-
-  Profile::TagOrder tag_order =
-      EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
-  intptr_t extra_tags = 0;
-  if (BoolParameter::Parse(js->LookupParam("_codeTransitionTags"))) {
-    extra_tags |= ProfilerService::kCodeTransitionTagsBit;
-  }
+static bool GetCpuSamples(Thread* thread, JSONStream* js) {
   int64_t time_origin_micros =
       Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
   int64_t time_extent_micros =
       Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
-  ProfilerService::PrintJSON(js, tag_order, extra_tags, time_origin_micros,
-                             time_extent_micros);
-  return true;
-}
-
-static const MethodParameter* get_cpu_profile_timeline_params[] = {
-    RUNNABLE_ISOLATE_PARAMETER,
-    new EnumParameter("tags", true, tags_enum_names),
-    new Int64Parameter("timeOriginMicros", false),
-    new Int64Parameter("timeExtentMicros", false),
-    NULL,
-};
-
-static bool GetCpuProfileTimeline(Thread* thread, JSONStream* js) {
+  const bool include_code_samples =
+      BoolParameter::Parse(js->LookupParam("_code"), false);
   if (CheckProfilerDisabled(thread, js)) {
     return true;
   }
-
-  Profile::TagOrder tag_order =
-      EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
-  int64_t time_origin_micros =
-      Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
-  int64_t time_extent_micros =
-      Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
-  bool code_trie = BoolParameter::Parse(js->LookupParam("code"), false);
-  ProfilerService::PrintTimelineJSON(js, tag_order, time_origin_micros,
-                                     time_extent_micros, code_trie);
-  return true;
-}
-
-static const MethodParameter* write_cpu_profile_timeline_params[] = {
-    RUNNABLE_ISOLATE_PARAMETER,
-    new EnumParameter("tags", true, tags_enum_names),
-    new Int64Parameter("timeOriginMicros", false),
-    new Int64Parameter("timeExtentMicros", false),
-    NULL,
-};
-
-static bool WriteCpuProfileTimeline(Thread* thread, JSONStream* js) {
-  if (CheckProfilerDisabled(thread, js)) {
-    return true;
-  }
-
-  Profile::TagOrder tag_order =
-      EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
-  int64_t time_origin_micros =
-      Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
-  int64_t time_extent_micros =
-      Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
-  bool code_trie = BoolParameter::Parse(js->LookupParam("code"), true);
-  ProfilerService::AddToTimeline(tag_order, time_origin_micros,
-                                 time_extent_micros, code_trie);
-  PrintSuccess(js);  // The "result" is a side-effect in the timeline.
+  ProfilerService::PrintJSON(js, time_origin_micros, time_extent_micros,
+                             include_code_samples);
   return true;
 }
 
 static const MethodParameter* get_allocation_samples_params[] = {
     RUNNABLE_ISOLATE_PARAMETER,
-    new EnumParameter("tags", true, tags_enum_names),
     new IdParameter("classId", false),
     new Int64Parameter("timeOriginMicros", false),
     new Int64Parameter("timeExtentMicros", false),
@@ -3929,8 +3859,6 @@
 };
 
 static bool GetAllocationSamples(Thread* thread, JSONStream* js) {
-  Profile::TagOrder tag_order =
-      EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
   int64_t time_origin_micros =
       Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
   int64_t time_extent_micros =
@@ -3940,8 +3868,11 @@
   GetPrefixedIntegerId(class_id, "classes/", &cid);
   Isolate* isolate = thread->isolate();
   if (IsValidClassId(isolate, cid)) {
+    if (CheckProfilerDisabled(thread, js)) {
+      return true;
+    }
     const Class& cls = Class::Handle(GetClassForId(isolate, cid));
-    ProfilerService::PrintAllocationJSON(js, tag_order, cls, time_origin_micros,
+    ProfilerService::PrintAllocationJSON(js, cls, time_origin_micros,
                                          time_extent_micros);
   } else {
     PrintInvalidParamError(js, "classId");
@@ -3951,32 +3882,38 @@
 
 static const MethodParameter* get_native_allocation_samples_params[] = {
     NO_ISOLATE_PARAMETER,
-    new EnumParameter("tags", true, tags_enum_names),
     new Int64Parameter("timeOriginMicros", false),
     new Int64Parameter("timeExtentMicros", false),
     NULL,
 };
 
 static bool GetNativeAllocationSamples(Thread* thread, JSONStream* js) {
-  Profile::TagOrder tag_order =
-      EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
   int64_t time_origin_micros =
       Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
   int64_t time_extent_micros =
       Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
+  bool include_code_samples =
+      BoolParameter::Parse(js->LookupParam("_code"), false);
 #if defined(DEBUG)
   Isolate::Current()->heap()->CollectAllGarbage();
 #endif
-  ProfilerService::PrintNativeAllocationJSON(js, tag_order, time_origin_micros,
-                                             time_extent_micros);
+  if (CheckProfilerDisabled(thread, js)) {
+    return true;
+  }
+  ProfilerService::PrintNativeAllocationJSON(
+      js, time_origin_micros, time_extent_micros, include_code_samples);
   return true;
 }
 
-static const MethodParameter* clear_cpu_profile_params[] = {
-    RUNNABLE_ISOLATE_PARAMETER, NULL,
+static const MethodParameter* clear_cpu_samples_params[] = {
+    RUNNABLE_ISOLATE_PARAMETER,
+    NULL,
 };
 
-static bool ClearCpuProfile(Thread* thread, JSONStream* js) {
+static bool ClearCpuSamples(Thread* thread, JSONStream* js) {
+  if (CheckProfilerDisabled(thread, js)) {
+    return true;
+  }
   ProfilerService::ClearSamples();
   PrintSuccess(js);
   return true;
@@ -4029,17 +3966,6 @@
   return GetAllocationProfileImpl(thread, js, true);
 }
 
-static const MethodParameter* collect_all_garbage_params[] = {
-    RUNNABLE_ISOLATE_PARAMETER, NULL,
-};
-
-static bool CollectAllGarbage(Thread* thread, JSONStream* js) {
-  Isolate* isolate = thread->isolate();
-  isolate->heap()->CollectAllGarbage(Heap::kDebugging);
-  PrintSuccess(js);
-  return true;
-}
-
 static const MethodParameter* get_heap_map_params[] = {
     RUNNABLE_ISOLATE_PARAMETER, NULL,
 };
@@ -4778,8 +4704,8 @@
     add_breakpoint_at_activation_params },
   { "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope,
     build_expression_evaluation_scope_params },
-  { "_clearCpuProfile", ClearCpuProfile,
-    clear_cpu_profile_params },
+  { "clearCpuSamples", ClearCpuSamples,
+    clear_cpu_samples_params },
   { "clearVMTimeline", ClearVMTimeline,
     clear_vm_timeline_params, },
   { "_compileExpression", CompileExpression, compile_expression_params },
@@ -4799,12 +4725,8 @@
       get_native_allocation_samples_params },
   { "getClassList", GetClassList,
     get_class_list_params },
-  { "_getCpuProfile", GetCpuProfile,
-    get_cpu_profile_params },
-  { "_getCpuProfileTimeline", GetCpuProfileTimeline,
-    get_cpu_profile_timeline_params },
-  { "_writeCpuProfileTimeline", WriteCpuProfileTimeline,
-    write_cpu_profile_timeline_params },
+  { "getCpuSamples", GetCpuSamples,
+    get_cpu_samples_params },
   { "getFlagList", GetFlagList,
     get_flag_list_params },
   { "_getHeapMap", GetHeapMap,
@@ -4891,8 +4813,6 @@
     set_vm_name_params },
   { "setVMTimelineFlags", SetVMTimelineFlags,
     set_vm_timeline_flags_params },
-  { "_collectAllGarbage", CollectAllGarbage,
-    collect_all_garbage_params },
   { "_getDefaultClassesAliases", GetDefaultClassesAliases,
     get_default_classes_aliases_params },
 };
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 453e872..d1ce7a7 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
 namespace dart {
 
 #define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 26
+#define SERVICE_PROTOCOL_MINOR_VERSION 27
 
 class Array;
 class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index b0ae846..b91b660 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.26
+# Dart VM Service Protocol 3.27
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 3.25_ of the Dart VM Service Protocol. This
+This document describes of _version 3.27_ of the Dart VM Service Protocol. This
 protocol is used to communicate with a running Dart Virtual Machine.
 
 To use the Service Protocol, start the VM with the *--observe* flag.
@@ -27,10 +27,12 @@
   - [addBreakpoint](#addbreakpoint)
   - [addBreakpointWithScriptUri](#addbreakpointwithscripturi)
   - [addBreakpointAtEntry](#addbreakpointatentry)
+  - [clearCpuSamples](#clearcpusamples)
   - [clearVMTimeline](#clearvmtimeline)
   - [evaluate](#evaluate)
   - [evaluateInFrame](#evaluateinframe)
   - [getAllocationProfile](#getallocationprofile)
+  - [getCpuSamples](#getcpusamples)
   - [getFlagList](#getflaglist)
   - [getInstances](#getinstances)
   - [getInboundReferences](#getinboundreferences)
@@ -73,6 +75,8 @@
   - [CodeKind](#codekind)
   - [Context](#context)
   - [ContextElement](#contextelement)
+  - [CpuSamples](#cpusamples)
+  - [CpuSample](#cpusample)
   - [Error](#error)
   - [ErrorKind](#errorkind)
   - [Event](#event)
@@ -94,6 +98,7 @@
   - [MapAssociation](#mapassociation)
   - [MemoryUsage](#memoryusage)
   - [Message](#message)
+  - [NativeFunction](#nativefunction)
   - [Null](#null)
   - [Object](#object)
   - [ReloadReport](#reloadreport)
@@ -509,6 +514,15 @@
 
 Note that breakpoints are added and removed on a per-isolate basis.
 
+### clearCpuSamples
+
+```
+Success clearCpuSamples(string isolateId)
+```
+
+Clears all CPU profiling samples.
+
+See [Success](#success).
 
 ### clearVMTimeline
 
@@ -651,6 +665,22 @@
 before collecting allocation information. There is no guarantee that a garbage
 collection will be actually be performed.
 
+### getCpuSamples
+
+```
+CpuSamples getCpuSamples(string isolateId,
+                         int timeOriginMicros,
+                         int timeExtentMicros)
+```
+
+The _getCpuSamples_ RPC is used to retrieve samples collected by the CPU
+profiler. Only samples collected in the time range `[timeOriginMicros,
+timeOriginMicros + timeExtentMicros]` will be reported.
+
+If the profiler is disabled, an error response will be returned.
+
+See [CpuSamples](#cpusamples).
+
 ### getFlagList
 
 ```
@@ -1549,6 +1579,83 @@
 }
 ```
 
+### CpuSamples
+
+```
+class CpuSamples extends Response {
+  // The sampling rate for the profiler in microseconds.
+  int samplePeriod;
+
+  // The maximum possible stack depth for samples.
+  int maxStackDepth;
+
+  // The number of samples returned.
+  int sampleCount;
+
+  // The timespan the set of returned samples covers, in microseconds.
+  int timeSpan;
+
+  // The start of the period of time in which the returned samples were
+  // collected.
+  int timeOriginMicros;
+
+  // The duration of time covered by the returned samples.
+  int timeExtentMicros;
+
+  // The process ID for the VM.
+  int pid;
+
+  // A list of functions seen in the relevant samples. These references can be
+  // looked up using the indicies provided in a `CpuSample` `stack` to determine
+  // which function was on the stack.
+  ProfileFunction[] functions;
+
+  // A list of samples collected in the range
+  // `[timeOriginMicros, timeOriginMicros + timeExtentMicros]`
+  CpuSample[] samples;
+}
+```
+
+See [getCpuSamples](#getcpusamples) and [CpuSample](#cpusample).
+
+### CpuSample
+
+```
+class CpuSample {
+  // The thread ID representing the thread on which this sample was collected.
+  int tid;
+
+  // The time this sample was collected in microseconds.
+  int timestamp;
+
+  // The name of VM tag set when this sample was collected. Omitted if the VM
+  // tag for the sample is not considered valid.
+  string vmTag [optional];
+
+  // The name of the User tag set when this sample was collected. Omitted if no
+  // User tag was set when this sample was collected.
+  string userTag [optional];
+
+  // Provided and set to true if the sample's stack was truncated. This can
+  // happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
+  // response.
+  bool truncated [optional];
+
+  // The call stack at the time this sample was collected. The stack is to be
+  // interpreted as top to bottom. Each element in this array is a key into the
+  // `functions` array in `CpuSamples`.
+  //
+  // Example:
+  //
+  // `functions[stack[0]] = @Function(bar())`
+  // `functions[stack[1]] = @Function(foo())`
+  // `functions[stack[2]] = @Function(main())`
+  int[] stack;
+}
+```
+
+See [getCpuSamples](#getcpusamples) and [CpuSamples](#cpusamples).
+
 ### Error
 
 ```
@@ -2088,6 +2195,18 @@
   // Provided for instance kinds:
   //   RegExp
   @Instance pattern [optional];
+
+  // The function associated with a Closure instance.
+  //
+  // Provided for instance kinds:
+  //   Closure
+  @Function closureFunction [optional];
+
+  // The context associated with a Closure instance.
+  //
+  // Provided for instance kinds:
+  //   Closure
+  @Context closureContext [optional];
 }
 ```
 
@@ -2239,18 +2358,6 @@
   //   Float64x2List
   string bytes [optional];
 
-  // The function associated with a Closure instance.
-  //
-  // Provided for instance kinds:
-  //   Closure
-  @Function closureFunction [optional];
-
-  // The context associated with a Closure instance.
-  //
-  // Provided for instance kinds:
-  //   Closure
-  @Context closureContext [optional];
-
   // The referent of a MirrorReference instance.
   //
   // Provided for instance kinds:
@@ -2690,6 +2797,17 @@
 A _Message_ provides information about a pending isolate message and the
 function that will be invoked to handle it.
 
+### NativeFunction
+
+```
+class NativeFunction {
+  // The name of the native function this object represents.
+  string name;
+}
+```
+
+A _NativeFunction_ object is used to represent native functions in profiler
+samples. See [CpuSamples](#cpusamples);
 
 ### Null
 
@@ -2764,6 +2882,33 @@
 
 An _Object_ is a  persistent object that is owned by some isolate.
 
+### ProfileFunction
+
+```
+class ProfileFunction {
+  // The kind of function this object represents.
+  string kind;
+
+  // The number of times function appeared on the stack during sampling events.
+  int inclusiveTicks;
+
+  // The number of times function appeared on the top of the stack during
+  // sampling events.
+  int exclusiveTicks;
+
+  // The resolved URL for the script containing function.
+  string resolvedUrl;
+
+  // The function captured during profiling.
+  (@Function|NativeFunction) function;
+}
+```
+
+A _ProfileFunction_ contains profiling information about a Dart or native
+function.
+
+See [CpuSamples](#cpusamples).
+
 ### ReloadReport
 
 ```
@@ -3323,5 +3468,6 @@
 3.24 | Add `operatingSystem` property to `VM` object.
 3.25 | Add 'getInboundReferences', 'getRetainingPath' RPCs, and 'InboundReferences', 'InboundReference', 'RetainingPath', and 'RetainingObject' objects.
 3.26 | Add 'requestHeapSnapshot'.
+3.27 | Add 'clearCpuSamples', 'getCpuSamples' RPCs and 'CpuSamples', 'CpuSample' objects.
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index a0206b5..b01182b 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -81,6 +81,7 @@
 Dart_Port ServiceIsolate::load_port_ = ILLEGAL_PORT;
 Dart_Port ServiceIsolate::origin_ = ILLEGAL_PORT;
 char* ServiceIsolate::server_address_ = NULL;
+char* ServiceIsolate::startup_failure_reason_ = nullptr;
 
 void ServiceIsolate::RequestServerInfo(const SendPort& sp) {
   const Array& message = Array::Handle(MakeServerControlMessage(
@@ -128,7 +129,7 @@
 
 bool ServiceIsolate::IsServiceIsolate(const Isolate* isolate) {
   MonitorLocker ml(monitor_);
-  return isolate == isolate_;
+  return isolate != nullptr && isolate == isolate_;
 }
 
 bool ServiceIsolate::IsServiceIsolateDescendant(const Isolate* isolate) {
@@ -161,7 +162,8 @@
 
 bool ServiceIsolate::SendServiceRpc(uint8_t* request_json,
                                     intptr_t request_json_length,
-                                    Dart_Port reply_port) {
+                                    Dart_Port reply_port,
+                                    char** error) {
   // Keep in sync with "sdk/lib/vmservice/vmservice.dart:_handleNativeRpcCall".
   Dart_CObject opcode;
   opcode.type = Dart_CObject_kInt32;
@@ -190,7 +192,25 @@
   request.value.as_array.length = ARRAY_SIZE(request_array);
 
   ServiceIsolate::WaitForLoadPortInternal();
-  return Dart_PostCObject(ServiceIsolate::Port(), &request);
+  Dart_Port service_port = ServiceIsolate::Port();
+
+  const bool success = Dart_PostCObject(service_port, &request);
+
+  if (!success && error != nullptr) {
+    if (service_port == ILLEGAL_PORT) {
+      if (startup_failure_reason_ != nullptr) {
+        *error = OS::SCreate(/*zone=*/nullptr,
+                             "Service isolate failed to start up: %s.",
+                             startup_failure_reason_);
+      } else {
+        *error = strdup("No service isolate port was found.");
+      }
+    } else {
+      *error = strdup("Was unable to post message to service isolate.");
+    }
+  }
+
+  return success;
 }
 
 bool ServiceIsolate::SendIsolateStartupMessage() {
@@ -318,10 +338,11 @@
   ml.NotifyAll();
 }
 
-void ServiceIsolate::InitializingFailed() {
+void ServiceIsolate::InitializingFailed(char* error) {
   MonitorLocker ml(monitor_);
   ASSERT(state_ == kStarting);
   state_ = kStopped;
+  startup_failure_reason_ = error;
   ml.NotifyAll();
 }
 
@@ -350,10 +371,15 @@
                      ": Isolate creation error: %s\n",
                      error);
       }
+
+      char* formatted_error = OS::SCreate(
+          /*zone=*/nullptr, "Invoking the 'create_group' failed with: '%s'",
+          error);
+
       free(error);
       error = nullptr;
       ServiceIsolate::SetServiceIsolate(NULL);
-      ServiceIsolate::InitializingFailed();
+      ServiceIsolate::InitializingFailed(formatted_error);
       return;
     }
 
@@ -484,7 +510,8 @@
   // that change this after Dart_Initialize returns.
   create_group_callback_ = Isolate::CreateGroupCallback();
   if (create_group_callback_ == NULL) {
-    ServiceIsolate::InitializingFailed();
+    ServiceIsolate::InitializingFailed(
+        strdup("The 'create_group' callback was not provided"));
     return;
   }
   bool task_started = Dart::thread_pool()->Run<RunServiceTask>();
@@ -547,6 +574,11 @@
     free(server_address_);
     server_address_ = NULL;
   }
+
+  if (startup_failure_reason_ != nullptr) {
+    free(startup_failure_reason_);
+    startup_failure_reason_ = nullptr;
+  }
 }
 
 void ServiceIsolate::BootVmServiceLibrary() {
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 25cef69..a3c1fdf 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -32,9 +32,14 @@
 
   // Returns `true` if the request was sucessfully sent.  If it was, the
   // [reply_port] will receive a Dart_TypedData_kUint8 response json.
+  //
+  // If sending the rpc failed and [error] is not `nullptr` then [error] might
+  // be set to a string containting the reason for the failure. If so, the
+  // caller is responsible for free()ing the error.
   static bool SendServiceRpc(uint8_t* request_json,
                              intptr_t request_json_length,
-                             Dart_Port reply_port);
+                             Dart_Port reply_port,
+                             char** error);
 
   static void Run();
   static bool SendIsolateStartupMessage();
@@ -66,7 +71,7 @@
   static void SetLoadPort(Dart_Port port);
   static void FinishedExiting();
   static void FinishedInitializing();
-  static void InitializingFailed();
+  static void InitializingFailed(char* error);
   static void MaybeMakeServiceIsolate(Isolate* isolate);
   static Dart_IsolateGroupCreateCallback create_group_callback() {
     return create_group_callback_;
@@ -87,6 +92,10 @@
   static Dart_Port origin_;
   static char* server_address_;
 
+  // If starting the service-isolate failed, this error might provide the reason
+  // for the failure.
+  static char* startup_failure_reason_;
+
   friend class Dart;
   friend class Isolate;
   friend class RunServiceTask;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 63ea6eb..7ba614a 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -718,25 +718,11 @@
   }
 
   Array& service_msg = Array::Handle();
-  service_msg = Eval(lib, "[0, port, '0', '_getCpuProfile', [], []]");
-  HandleIsolateMessage(isolate, service_msg);
-  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
-  // Expect error (tags required).
-  EXPECT_SUBSTRING("\"error\"", handler.msg());
-
-  service_msg =
-      Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['None']]");
+  service_msg = Eval(lib, "[0, port, '0', 'getCpuSamples', [], []]");
   HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect profile
-  EXPECT_SUBSTRING("\"type\":\"_CpuProfile\"", handler.msg());
-
-  service_msg =
-      Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['Bogus']]");
-  HandleIsolateMessage(isolate, service_msg);
-  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
-  // Expect error.
-  EXPECT_SUBSTRING("\"error\"", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"CpuSamples\"", handler.msg());
 }
 
 #endif  // !defined(TARGET_ARCH_ARM64)
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 65258de..7fbc4d5 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -636,7 +636,7 @@
 
   const char* version = reinterpret_cast<const char*>(CurrentBufferAddress());
   ASSERT(version != NULL);
-  if (strncmp(version, expected_version, version_len)) {
+  if (strncmp(version, expected_version, version_len) != 0) {
     const intptr_t kMessageBufferSize = 256;
     char message_buffer[kMessageBufferSize];
     char* actual_version = Utils::StrNDup(version, version_len);
@@ -660,7 +660,7 @@
   ASSERT(features != NULL);
   intptr_t buffer_len = Utils::StrNLen(features, PendingBytes());
   if ((buffer_len != expected_len) ||
-      strncmp(features, expected_features, expected_len)) {
+      (strncmp(features, expected_features, expected_len) != 0)) {
     const intptr_t kMessageBufferSize = 256;
     char message_buffer[kMessageBufferSize];
     char* actual_features =
@@ -959,10 +959,13 @@
       nodes_(),
       first_unprocessed_object_id_(first_object_id) {
   ASSERT(first_object_id > 0);
+  isolate()->set_forward_table_new(new WeakTable());
+  isolate()->set_forward_table_old(new WeakTable());
 }
 
 ForwardList::~ForwardList() {
-  heap()->ResetObjectIdTable();
+  isolate()->set_forward_table_new(nullptr);
+  isolate()->set_forward_table_old(nullptr);
 }
 
 intptr_t ForwardList::AddObject(Zone* zone,
@@ -976,17 +979,33 @@
   ASSERT(node != NULL);
   nodes_.Add(node);
   ASSERT(object_id != 0);
-  heap()->SetObjectId(raw, object_id);
+  SetObjectId(raw, object_id);
   return object_id;
 }
 
 intptr_t ForwardList::FindObject(RawObject* raw) {
   NoSafepointScope no_safepoint;
-  intptr_t id = heap()->GetObjectId(raw);
+  intptr_t id = GetObjectId(raw);
   ASSERT(id == 0 || NodeForObjectId(id)->obj()->raw() == raw);
   return (id == 0) ? static_cast<intptr_t>(kInvalidIndex) : id;
 }
 
+void ForwardList::SetObjectId(RawObject* object, intptr_t id) {
+  if (object->IsNewObject()) {
+    isolate()->forward_table_new()->SetValue(object, id);
+  } else {
+    isolate()->forward_table_old()->SetValue(object, id);
+  }
+}
+
+intptr_t ForwardList::GetObjectId(RawObject* object) {
+  if (object->IsNewObject()) {
+    return isolate()->forward_table_new()->GetValue(object);
+  } else {
+    return isolate()->forward_table_old()->GetValue(object);
+  }
+}
+
 bool SnapshotWriter::CheckAndWritePredefinedObject(RawObject* rawobj) {
   // Check if object can be written in one of the following ways:
   // - Smi: the Smi value is written as is (last bit is not tagged).
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 5f6c929..5c3b68e 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -196,9 +196,6 @@
   const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
 
   const uint8_t* DataImage() const {
-    if (!IncludesCode(kind())) {
-      return NULL;
-    }
     uword offset = Utils::RoundUp(length(), OS::kMaxPreferredCodeAlignment);
     return Addr() + offset;
   }
@@ -255,6 +252,7 @@
     return stream_.AddressOfCurrentPosition();
   }
 
+  void Align(intptr_t value) { stream_.Align(value); }
   void Advance(intptr_t value) { stream_.Advance(value); }
 
   intptr_t PendingBytes() const { return stream_.PendingBytes(); }
@@ -517,6 +515,8 @@
     Write<int8_t>(static_cast<int8_t>(flags));
   }
 
+  void Align(intptr_t value) { stream_.Align(value); }
+
   // Write out a buffer of bytes.
   void WriteBytes(const uint8_t* addr, intptr_t len) {
     stream_.WriteBytes(addr, len);
@@ -605,13 +605,16 @@
  private:
   intptr_t first_object_id() const { return first_object_id_; }
   intptr_t next_object_id() const { return nodes_.length() + first_object_id_; }
-  Heap* heap() const { return thread_->isolate()->heap(); }
+  Isolate* isolate() const { return thread_->isolate(); }
 
   Thread* thread_;
   const intptr_t first_object_id_;
   GrowableArray<Node*> nodes_;
   intptr_t first_unprocessed_object_id_;
 
+  void SetObjectId(RawObject* object, intptr_t id);
+  intptr_t GetObjectId(RawObject* object);
+
   DISALLOW_COPY_AND_ASSIGN(ForwardList);
 };
 
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index e05f475..3da6666 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -724,7 +724,8 @@
       "}\n";
   Dart_Handle result;
 
-  uint8_t* isolate_snapshot_data_buffer;
+  uint8_t* isolate_snapshot_data_buffer = nullptr;
+  intptr_t isolate_snapshot_data_size = 0;
 
   // Start an Isolate, load a script and create a full snapshot.
   Timer timer1(true, "Snapshot_test");
@@ -749,17 +750,38 @@
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
     // Write snapshot with object content.
-    FullSnapshotWriter writer(Snapshot::kFull, NULL,
+    uint8_t* isolate_snapshot_text_buffer = nullptr;
+    BlobImageWriter image_writer(thread, &isolate_snapshot_text_buffer,
+                                 &malloc_allocator, 2 * MB /* initial_size */,
+                                 /*shared_objects=*/nullptr,
+                                 /*shared_instructions=*/nullptr,
+                                 /*reused_instructions=*/nullptr);
+    FullSnapshotWriter writer(Snapshot::kFull, nullptr,
                               &isolate_snapshot_data_buffer, &malloc_allocator,
-                              NULL, /*image_writer*/ nullptr);
+                              nullptr, &image_writer);
     writer.WriteFullSnapshot();
+    isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+    free(isolate_snapshot_text_buffer);
   }
 
+  // Malloc gives only 8 byte alignment, but we need
+  // OS::kMaxPreferredCodeAlignment. Rellocate to VirtualMemory to get page
+  // alignment.
+  std::unique_ptr<VirtualMemory> aligned_isolate_snapshot_data_buffer(
+      VirtualMemory::Allocate(
+          Utils::RoundUp(isolate_snapshot_data_size, VirtualMemory::PageSize()),
+          false, "snapshot_test"));
+  memmove(aligned_isolate_snapshot_data_buffer->address(),
+          isolate_snapshot_data_buffer, isolate_snapshot_data_size);
+  free(isolate_snapshot_data_buffer);
+  isolate_snapshot_data_buffer = nullptr;
+
   // Now Create another isolate using the snapshot and execute a method
   // from the script.
   Timer timer2(true, "Snapshot_test");
   timer2.Start();
-  TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
+  TestCase::CreateTestIsolateFromSnapshot(reinterpret_cast<uint8_t*>(
+      aligned_isolate_snapshot_data_buffer->address()));
   {
     Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
     timer2.Stop();
@@ -772,7 +794,6 @@
     Dart_ExitScope();
   }
   Dart_ShutdownIsolate();
-  free(isolate_snapshot_data_buffer);
 }
 
 // Helper function to call a top level Dart function and serialize the result.
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 30bf604..59bc7a3 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -5,6 +5,7 @@
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 #include "vm/source_report.h"
 
+#include "vm/bit_vector.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/isolate.h"
 #include "vm/kernel_loader.h"
@@ -57,8 +58,7 @@
     // Build the profile.
     SampleFilter samplesForIsolate(thread_->isolate()->main_port(),
                                    Thread::kMutatorTask, -1, -1);
-    profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer(),
-                   Profile::kNoTags);
+    profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer());
   }
 }
 
@@ -330,11 +330,8 @@
   const TokenPosition begin_pos = func.token_pos();
   const TokenPosition end_pos = func.end_token_pos();
   intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1;
-  GrowableArray<char> possible(func_length);
-  possible.SetLength(func_length);
-  for (int i = 0; i < func_length; i++) {
-    possible[i] = false;
-  }
+
+  BitVector possible(zone(), func_length);
 
   if (code.IsNull()) {
     const Bytecode& bytecode = Bytecode::Handle(func.bytecode());
@@ -354,7 +351,7 @@
           // source position range.
           if (bytecode.GetDebugCheckedOpcodeReturnAddress(
                   pc_offset, iter.PcOffset()) != 0) {
-            possible[token_offset] = true;
+            possible.Add(token_offset);
           }
           pc_offset = kUwordMax;
         }
@@ -373,7 +370,7 @@
     }
     if (pc_offset != kUwordMax && bytecode.GetDebugCheckedOpcodeReturnAddress(
                                       pc_offset, bytecode.Size()) != 0) {
-      possible[token_offset] = true;
+      possible.Add(token_offset);
     }
   } else {
     const uint8_t kSafepointKind =
@@ -391,13 +388,13 @@
         continue;
       }
       intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
-      possible[token_offset] = true;
+      possible.Add(token_offset);
     }
   }
 
   JSONArray bpts(jsobj, "possibleBreakpoints");
   for (int i = 0; i < func_length; i++) {
-    if (possible[i]) {
+    if (possible.Contains(i)) {
       // Add the token position.
       bpts.AddValue(begin_pos.Pos() + i);
     }
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 0e61b72..2bdde95 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -515,8 +515,8 @@
   ExceptionHandlerInfo* info = cache->Lookup(pc());
   if (info != NULL) {
     *handler_pc = start + info->handler_pc_offset;
-    *needs_stacktrace = info->needs_stacktrace;
-    *has_catch_all = info->has_catch_all;
+    *needs_stacktrace = (info->needs_stacktrace != 0);
+    *has_catch_all = (info->has_catch_all != 0);
     return true;
   }
 
@@ -544,8 +544,8 @@
   ExceptionHandlerInfo handler_info;
   handlers.GetHandlerInfo(try_index, &handler_info);
   *handler_pc = start + handler_info.handler_pc_offset;
-  *needs_stacktrace = handler_info.needs_stacktrace;
-  *has_catch_all = handler_info.has_catch_all;
+  *needs_stacktrace = (handler_info.needs_stacktrace != 0);
+  *has_catch_all = (handler_info.has_catch_all != 0);
   cache->Insert(pc(), handler_info);
   return true;
 }
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index fba676e..b36721d 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -56,7 +56,7 @@
     return 0;
   }
 
-  uword IsMarkedForLazyDeopt() const {
+  bool IsMarkedForLazyDeopt() const {
     ASSERT(!is_interpreted());
     uword raw_pc =
         *reinterpret_cast<uword*>(sp() + (kSavedPcSlotFromSp * kWordSize));
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index 6413989..c423a84 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_STACK_FRAME_ARM_H_
 #define RUNTIME_VM_STACK_FRAME_ARM_H_
 
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_arm.h directly; use stack_frame.h instead.
+#endif
+
 namespace dart {
 
 /* ARM Dart Frame Layout
diff --git a/runtime/vm/stack_frame_arm64.h b/runtime/vm/stack_frame_arm64.h
index abaa49a..1558a22 100644
--- a/runtime/vm/stack_frame_arm64.h
+++ b/runtime/vm/stack_frame_arm64.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_STACK_FRAME_ARM64_H_
 #define RUNTIME_VM_STACK_FRAME_ARM64_H_
 
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_arm64.h directly; use stack_frame.h instead.
+#endif
+
 namespace dart {
 
 /* ARM64 Dart Frame Layout
diff --git a/runtime/vm/stack_frame_dbc.h b/runtime/vm/stack_frame_dbc.h
index 42a1b79..616b012 100644
--- a/runtime/vm/stack_frame_dbc.h
+++ b/runtime/vm/stack_frame_dbc.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_STACK_FRAME_DBC_H_
 #define RUNTIME_VM_STACK_FRAME_DBC_H_
 
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_dbc.h directly; use stack_frame.h instead.
+#endif
+
 namespace dart {
 
 /* DBC Frame Layout
diff --git a/runtime/vm/stack_frame_ia32.h b/runtime/vm/stack_frame_ia32.h
index 896fb05..c8221ee 100644
--- a/runtime/vm/stack_frame_ia32.h
+++ b/runtime/vm/stack_frame_ia32.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_STACK_FRAME_IA32_H_
 #define RUNTIME_VM_STACK_FRAME_IA32_H_
 
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_ia32.h directly; use stack_frame.h instead.
+#endif
+
 namespace dart {
 
 /* IA32 Dart Frame Layout
diff --git a/runtime/vm/stack_frame_kbc.h b/runtime/vm/stack_frame_kbc.h
index 3418eaa..6af9a3a 100644
--- a/runtime/vm/stack_frame_kbc.h
+++ b/runtime/vm/stack_frame_kbc.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_STACK_FRAME_KBC_H_
 #define RUNTIME_VM_STACK_FRAME_KBC_H_
 
+#include "platform/globals.h"
+
 namespace dart {
 
 /* Kernel Bytecode Frame Layout
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index 76a31f8..15800b7 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -149,7 +149,7 @@
   int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
   for (int i = 0; i < num_entries; i++) {
     struct NativeEntries* entry = &(BuiltinEntries[i]);
-    if (!strcmp(function_name, entry->name_) &&
+    if ((strcmp(function_name, entry->name_) == 0) &&
         (entry->argument_count_ == argument_count)) {
       return reinterpret_cast<Dart_NativeFunction>(entry->function_);
     }
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index 1507960..dd01d67 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -5,6 +5,10 @@
 #ifndef RUNTIME_VM_STACK_FRAME_X64_H_
 #define RUNTIME_VM_STACK_FRAME_X64_H_
 
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_x64.h directly; use stack_frame.h instead.
+#endif
+
 #include "vm/constants_x64.h"
 
 namespace dart {
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index b21b28e..17724a3 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -85,7 +85,6 @@
       code_array.SetAt(array_offset, bytecode);
     } else {
       code = frame->LookupDartCode();
-      function = code.function();
       offset = Smi::New(frame->pc() - code.PayloadStart());
       code_array.SetAt(array_offset, code);
     }
diff --git a/runtime/vm/static_type_exactness_state.h b/runtime/vm/static_type_exactness_state.h
index 17e0089..a55f63a 100644
--- a/runtime/vm/static_type_exactness_state.h
+++ b/runtime/vm/static_type_exactness_state.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_
 
 #include "platform/allocation.h"
+#include "platform/utils.h"
 
 // This header defines the list of VM implementation classes and their ids.
 //
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 04e827b..31bb9e7 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -72,6 +72,9 @@
   V(DartExtensionScheme, "dart-ext:")                                          \
   V(DartFfi, "dart:ffi")                                                       \
   V(DartFfiLibName, "ffi")                                                     \
+  V(DartWasm, "dart:wasm")                                                     \
+  V(DartWasmLibName, "wasm")                                                   \
+  V(DartLibraryWasm, "dart.library.wasm")                                      \
   V(DartIOLibName, "dart.io")                                                  \
   V(DartInternal, "dart:_internal")                                            \
   V(DartIsVM, "dart.isVM")                                                     \
@@ -114,6 +117,7 @@
   V(ExternalTwoByteString, "_ExternalTwoByteString")                           \
   V(FactoryResult, "factory result")                                           \
   V(FallThroughError, "FallThroughError")                                      \
+  V(FfiCallback, "_FfiCallback")                                               \
   V(FfiDouble, "Double")                                                       \
   V(FfiDynamicLibrary, "DynamicLibrary")                                       \
   V(FfiFloat, "Float")                                                         \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 41a2afa..688e886 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -42,7 +42,7 @@
   // There should be no top api scopes at this point.
   ASSERT(api_top_scope() == NULL);
   // Delete the resusable api scope if there is one.
-  if (api_reusable_scope_) {
+  if (api_reusable_scope_ != nullptr) {
     delete api_reusable_scope_;
     api_reusable_scope_ = NULL;
   }
@@ -941,7 +941,7 @@
 }
 
 const intptr_t kInitialCallbackIdsReserved = 1024;
-int32_t Thread::AllocateFfiCallbackId(uword* trampoline) {
+int32_t Thread::AllocateFfiCallbackId() {
   Zone* Z = isolate()->current_zone();
   if (ffi_callback_code_ == GrowableObjectArray::null()) {
     ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved);
@@ -955,7 +955,7 @@
   if (NativeCallbackTrampolines::Enabled()) {
     auto* const tramps = isolate()->native_callback_trampolines();
     ASSERT(tramps->next_callback_id() == id);
-    *trampoline = tramps->AllocateTrampoline();
+    tramps->AllocateTrampoline();
   }
 #endif
 
@@ -964,7 +964,25 @@
 
 void Thread::SetFfiCallbackCode(int32_t callback_id, const Code& code) {
   Zone* Z = isolate()->current_zone();
+
+  /// In AOT the callback ID might have been allocated during compilation but
+  /// 'ffi_callback_code_' is initialized to empty again when the program
+  /// starts. Therefore we may need to initialize or expand it to accomodate
+  /// the callback ID.
+
+  if (ffi_callback_code_ == GrowableObjectArray::null()) {
+    ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved);
+  }
+
   const auto& array = GrowableObjectArray::Handle(Z, ffi_callback_code_);
+
+  if (callback_id >= array.Length()) {
+    if (callback_id >= array.Capacity()) {
+      array.Grow(callback_id + 1);
+    }
+    array.SetLength(callback_id + 1);
+  }
+
   array.SetAt(callback_id, code);
 }
 
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 894197a..b1fa522 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -14,6 +14,7 @@
 #include "platform/atomic.h"
 #include "platform/safe_stack.h"
 #include "vm/bitfield.h"
+#include "vm/compiler/runtime_api.h"
 #include "vm/constants.h"
 #include "vm/globals.h"
 #include "vm/handles.h"
@@ -23,7 +24,6 @@
 #include "vm/runtime_entry_list.h"
 #include "vm/thread_stack_resource.h"
 #include "vm/thread_state.h"
-
 namespace dart {
 
 class AbstractType;
@@ -786,7 +786,11 @@
     }
   }
 
-  int32_t AllocateFfiCallbackId(uword* trampoline);
+  int32_t AllocateFfiCallbackId();
+
+  // Store 'code' for the native callback identified by 'callback_id'.
+  //
+  // Expands the callback code array as necessary to accomodate the callback ID.
   void SetFfiCallbackCode(int32_t callback_id, const Code& code);
 
   // Ensure that 'callback_id' refers to a valid callback in this isolate.
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 8b9a644..bad38fd 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -737,10 +737,11 @@
     : name_(name),
       fuchsia_name_(fuchsia_name),
 #if defined(HOST_OS_FUCHSIA)
-      enabled_(true) {  // For generated code.
+      enabled_(static_cast<uintptr_t>(true))  // For generated code.
 #else
-      enabled_(enabled) {
+      enabled_(static_cast<uintptr_t>(enabled))
 #endif
+{
 }
 
 TimelineEvent* TimelineStream::StartEvent() {
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index ff8c682..844f9b9 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -259,6 +259,19 @@
     return tok_str_[tok];
   }
 
+  static bool FromStr(const char* str, Kind* out) {
+    ASSERT(str != nullptr && out != nullptr);
+#define TOK_CASE(t, s, p, a)                                                   \
+  if (strcmp(str, tok_str_[(t)]) == 0) {                                       \
+    *out = (t);                                                                \
+    return true;                                                               \
+  }
+    DART_TOKEN_LIST(TOK_CASE)
+    DART_KEYWORD_LIST(TOK_CASE)
+#undef TOK_CASE
+    return false;
+  }
+
   static int Precedence(Kind tok) {
     ASSERT(tok < kNumTokens);
     return precedence_[tok];
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index fcc057f..b692ab4 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -19,6 +19,8 @@
   "bootstrap.h",
   "bootstrap_natives.cc",
   "bootstrap_natives.h",
+  "bss_relocs.cc",
+  "bss_relocs.h",
   "class_finalizer.cc",
   "class_finalizer.h",
   "class_id.h",
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 88e1ef9..6f11bf7 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -82,13 +82,13 @@
     return false;
   }
 
+  // All pointers returned from AllocateUnsafe() and New() have this alignment.
+  static const intptr_t kAlignment = kDoubleSize;
+
  private:
   Zone();
   ~Zone();  // Delete all memory associated with the zone.
 
-  // All pointers returned from AllocateUnsafe() and New() have this alignment.
-  static const intptr_t kAlignment = kDoubleSize;
-
   // Default initial chunk size.
   static const intptr_t kInitialChunkSize = 1 * KB;
 
@@ -119,6 +119,7 @@
   void Free(ElementType* old_array, intptr_t len) {
 #ifdef DEBUG
     if (len > 0) {
+      ASSERT(old_array != nullptr);
       memset(old_array, kZapUninitializedByte, len * sizeof(ElementType));
     }
 #endif
diff --git a/samples/samples.status b/samples/samples.status
index b5f2b33..257e3a5 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -17,9 +17,6 @@
 [ $compiler == none && $runtime == vm && $system == fuchsia ]
 *: Skip # Not yet triaged.
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
 [ $arch != x64 || $compiler != dartk || $system != linux || $hot_reload || $hot_reload_rollback ]
 ffi/sqlite/test/sqlite_test: Skip # FFI not supported or libsqlite3.so not available.
 
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index b689dd2..228fc3c 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -84,6 +84,7 @@
 # ......math/
 # ......mirrors/
 # ......typed_data/
+# ......wasm/
 # ......api_readme.md
 # ....model/
 # ......lexeme/
@@ -116,6 +117,10 @@
     "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
   ],
   [
+    "dart2native",
+    "../utils/dart2native:generate_dart2native_snapshot",
+  ],
+  [
     "dartdoc",
     "../utils/dartdoc",
   ],
@@ -155,6 +160,10 @@
     "../utils/dartanalyzer:generate_dartanalyzer_snapshot",
   ],
   [
+    "dart2native",
+    "../utils/dart2native:generate_dart2native_snapshot",
+  ],
+  [
     "dartdevc",
     "../utils/dartdevc",
   ],
@@ -216,6 +225,7 @@
   "profiler",
   "svg",
   "typed_data",
+  "wasm",
   "web_audio",
   "web_gl",
   "web_sql",
@@ -249,22 +259,22 @@
 copy_tree_specs = []
 
 # This rule copies dartdoc templates to
-# bin/snapshots/resources/dartdoc/templates
+# bin/resources/dartdoc/templates
 copy_tree_specs += [ {
       target = "copy_dartdoc_templates"
       visibility = [ ":copy_dartdoc_files" ]
       source = "../third_party/pkg/dartdoc/lib/templates"
-      dest = "$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/templates"
+      dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/templates"
       ignore_patterns = "{}"
     } ]
 
 # This rule copies dartdoc resources to
-# bin/snapshots/resources/dartdoc/resources
+# bin/resources/dartdoc/resources
 copy_tree_specs += [ {
       target = "copy_dartdoc_resources"
       visibility = [ ":copy_dartdoc_files" ]
       source = "../third_party/pkg/dartdoc/lib/resources"
-      dest = "$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/resources"
+      dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/resources"
       ignore_patterns = "{}"
     } ]
 
@@ -421,9 +431,6 @@
       "$gen_snapshot_out/$gen_snapshot_stripped_binary",
     ]
   }
-  if (is_win) {
-    sources += [ "$gen_snapshot_out/gen_snapshot.lib" ]
-  }
   outputs = [
     "$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}",
   ]
@@ -442,6 +449,23 @@
   ]
 }
 
+copy("copy_dart2native") {
+  deps = [
+    ":copy_gen_kernel_snapshot",
+    ":copy_gen_snapshot",
+  ]
+  ext = ""
+  if (is_win) {
+    ext = ".bat"
+  }
+  sources = [
+    "bin/dart2native$ext",
+  ]
+  outputs = [
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+  ]
+}
+
 copy("copy_gen_kernel_snapshot") {
   deps = [
     "../utils/gen_kernel",
@@ -566,7 +590,7 @@
 }
 
 # This rule writes the .packages file for dartdoc resources.
-write_file("$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/.packages",
+write_file("$root_out_dir/dart-sdk/bin/resources/dartdoc/.packages",
            "dartdoc:.")
 
 # This is the main rule for copying the files that dartdoc needs.
@@ -978,6 +1002,7 @@
     ":copy_analysis_summaries",
     ":copy_api_readme",
     ":copy_dart",
+    ":copy_dart2native",
     ":copy_dartdoc_files",
     ":copy_headers",
     ":copy_libraries_dart",
diff --git a/sdk/bin/dart2native b/sdk/bin/dart2native
new file mode 100755
index 0000000..29f29d7
--- /dev/null
+++ b/sdk/bin/dart2native
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Run dart2native.dart.snapshot on the Dart VM
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
+DART="$BIN_DIR/dart"
+
+exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*
diff --git a/sdk/bin/dart2native.bat b/sdk/bin/dart2native.bat
new file mode 100644
index 0000000..631dce8
--- /dev/null
+++ b/sdk/bin/dart2native.bat
@@ -0,0 +1,43 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk/bin/dartdoc b/sdk/bin/dartdoc
index d81a581..e9584c1 100755
--- a/sdk/bin/dartdoc
+++ b/sdk/bin/dartdoc
@@ -3,9 +3,6 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
-# SDK's directory structure.
-
 function follow_links() {
   file="$1"
   while [ -h "$file" ]; do
@@ -26,4 +23,4 @@
 
 # We are running the snapshot in the built SDK.
 DART="$BIN_DIR/dart"
-exec "$DART" "--packages=$BIN_DIR/snapshots/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
+exec "$DART" "--packages=$BIN_DIR/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
diff --git a/sdk/bin/dartdoc.bat b/sdk/bin/dartdoc.bat
index 8c2c900..876eb0e 100644
--- a/sdk/bin/dartdoc.bat
+++ b/sdk/bin/dartdoc.bat
@@ -14,7 +14,7 @@
 set DART=%BIN_DIR%\dart
 set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
 
-"%DART%" "--packages=%BIN_DIR%/snapshots/resources/dartdoc/.packages" "%SNAPSHOT%" %*
+"%DART%" "--packages=%BIN_DIR%/resources/dartdoc/.packages" "%SNAPSHOT%" %*
 
 endlocal
 
diff --git a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
index f769673..91d6847 100644
--- a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
@@ -541,9 +541,7 @@
   return value;
 }
 
-// The allowInterop method is a no-op in Dart Dev Compiler.
-// TODO(jacobr): tag methods so we can throw if a Dart method is passed to
-// JavaScript using the new interop without calling allowInterop.
+Expando<Function> _interopExpando = Expando<Function>();
 
 /// Returns a wrapper around function [f] that can be called from JavaScript
 /// using the package:js Dart-JavaScript interop.
@@ -556,7 +554,20 @@
 /// JavaScript. We may remove the need to call this method completely in the
 /// future if Dart2Js is refactored so that its function calling conventions
 /// are more compatible with JavaScript.
-F allowInterop<F extends Function>(F f) => f;
+F allowInterop<F extends Function>(F f) {
+  var ret = _interopExpando[f];
+  if (ret == null) {
+    ret = JS(
+        '',
+        'function (...args) {'
+            ' return #(#, args);'
+            '}',
+        dart.dcall,
+        f);
+    _interopExpando[f] = ret;
+  }
+  return ret;
+}
 
 Expando<Function> _interopCaptureThisExpando = Expando<Function>();
 
@@ -571,13 +582,12 @@
   if (ret == null) {
     ret = JS(
         '',
-        'function(/*...arguments*/) {'
+        'function(...arguments) {'
             '  let args = [this];'
-            '  for (let arg of arguments) {'
-            '    args.push(arg);'
-            '  }'
-            '  return #(...args);'
+            '  args.push.apply(args, arguments);'
+            '  return #(#, args);'
             '}',
+        dart.dcall,
         f);
     _interopCaptureThisExpando[f] = ret;
   }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index bbde1a6..3175eeb 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -334,11 +334,16 @@
 })()''');
 
 class FunctionType extends AbstractFunctionType {
-  final returnType;
+  final Type returnType;
   List args;
   List optionals;
+  // Named arguments native JS Object of the form { namedArgName: namedArgType }
   final named;
   // TODO(vsm): This is just parameter metadata for now.
+  // Suspected but not confirmed: Only used by mirrors for pageloader2 support.
+  // The metadata is represented as a list of JS arrays, one for each argument
+  // that contains the annotations for that argument or an empty array if there
+  // are no annotations.
   List metadata = [];
   String _stringValue;
 
@@ -380,6 +385,11 @@
     return _memoizeArray(_fnTypeTypeMap, keys, create);
   }
 
+  /// Returns the function arguments.
+  ///
+  /// If an argument is provided with annotations (encoded as a JS array where
+  /// the first element is the argument, and the rest are annotations) the
+  /// annotations are extracted and saved in [metadata].
   List _process(List array) {
     var result = [];
     for (var i = 0; JS<bool>('!', '# < #.length', i, array); ++i) {
@@ -398,7 +408,8 @@
   FunctionType(this.returnType, this.args, this.optionals, this.named) {
     this.args = _process(this.args);
     this.optionals = _process(this.optionals);
-    // TODO(vsm): Add named arguments.
+    // TODO(vsm): Named arguments were never used by pageloader2 so they were
+    // never processed here.
   }
 
   toString() => name;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_names.dart b/sdk/lib/_internal/js_runtime/lib/js_names.dart
index 06b633a..cb4aa0e 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_names.dart
@@ -82,7 +82,7 @@
 }
 
 /// Implements the inverse of [_LazyMangledNamesMap]. As it would be too
-/// expensive to seach the mangled names map for a value that corresponds to
+/// expensive to search the mangled names map for a value that corresponds to
 /// the lookup key on each invocation, we compute the full mapping in demand
 /// and cache it. The cache is invalidated when the underlying [_jsMangledNames]
 /// object changes its length. This condition is sufficient as the name mapping
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index cfd6fa6..ba141fa 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -134,6 +134,8 @@
       categories: "Client",
       maturity: Maturity.WEB_STABLE,
       platforms: DART2JS_PLATFORM),
+  "wasm": const LibraryInfo("wasm/wasm.dart",
+      categories: "Server", maturity: Maturity.EXPERIMENTAL),
   "web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
       categories: "Client",
       maturity: Maturity.WEB_STABLE,
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index dce5b7e..02f9c98 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -194,14 +194,12 @@
     if (!_hasTimeline) return;
     ArgumentError.checkNotNull(name, 'name');
     var block = new _AsyncBlock._(name, _taskId);
-    if (arguments != null) {
-      block._arguments = arguments;
-    }
     _stack.add(block);
-    block._start();
+    block._start(arguments);
   }
 
   /// Emit an instant event for this task.
+  /// Optionally takes a [Map] of [arguments].
   void instant(String name, {Map arguments}) {
     if (!_hasTimeline) return;
     ArgumentError.checkNotNull(name, 'name');
@@ -214,7 +212,8 @@
   }
 
   /// Finish the last synchronous operation that was started.
-  void finish() {
+  /// Optionally takes a [Map] of [arguments].
+  void finish({Map arguments}) {
     if (!_hasTimeline) {
       return;
     }
@@ -223,7 +222,7 @@
     }
     // Pop top item off of stack.
     var block = _stack.removeLast();
-    block._finish();
+    block._finish(arguments);
   }
 
   /// Retrieve the [TimelineTask]'s task id. Will throw an exception if the
@@ -254,22 +253,18 @@
   /// The asynchronous task id.
   final int _taskId;
 
-  /// An (optional) set of arguments which will be serialized to JSON and
-  /// associated with this block.
-  Map _arguments;
-
   _AsyncBlock._(this.name, this._taskId);
 
   // Emit the start event.
-  void _start() {
-    _reportTaskEvent(
-        _getTraceClock(), _taskId, 'b', category, name, _argumentsAsJson(null));
+  void _start(Map arguments) {
+    _reportTaskEvent(_getTraceClock(), _taskId, 'b', category, name,
+        _argumentsAsJson(arguments));
   }
 
   // Emit the finish event.
-  void _finish() {
+  void _finish(Map arguments) {
     _reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name,
-        _argumentsAsJson(_arguments));
+        _argumentsAsJson(arguments));
   }
 }
 
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 85837e1..a975a13 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -2,8 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file
 
-/// {@category VM}
-/// {@nodoc}
+/**
+ * Foreign Function Interface for interoperability with the C programming language.
+ *
+ * **NOTE**: Dart:FFI is in technical preview. The overall feature is incomplete,
+ * may contain issues, and breaking API changes are still expected.
+ *
+ * For further details, please see: https://dart.dev/server/c-interop
+ *
+ * {@category VM}
+ */
 library dart.ffi;
 
 import 'dart:typed_data' show TypedData;
@@ -50,7 +58,8 @@
   /// Does not accept dynamic invocations -- where the type of the receiver is
   /// [dynamic].
   external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
-      @DartRepresentationOf("T") Function f, Object exceptionalReturn);
+      @DartRepresentationOf("T") Function f,
+      [Object exceptionalReturn]);
 
   /// Store a Dart value into this location.
   ///
diff --git a/sdk/lib/ffi/native_type.dart b/sdk/lib/ffi/native_type.dart
index bd88b28..aa30e63 100644
--- a/sdk/lib/ffi/native_type.dart
+++ b/sdk/lib/ffi/native_type.dart
@@ -121,13 +121,11 @@
 /// [Void] is not constructible in the Dart code and serves purely as marker in
 /// type signatures.
 @unsized
-class Void extends NativeType {
-  const Void();
-}
+abstract class Void extends NativeType {}
 
 /// Represents a function type in C.
 ///
 /// [NativeFunction] is not constructible in the Dart code and serves purely as
 /// marker in type signatures.
 @unsized
-class NativeFunction<T extends Function> extends NativeType {}
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 0736e06..303ec9e 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -28281,11 +28281,12 @@
    *
    * See also:
    *
-   * * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#innerhtml-on-templates>
+   * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
    */
   void setInnerHtml(String html,
       {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
     text = null;
+    content.nodes.clear();
     var fragment = createFragment(html,
         validator: validator, treeSanitizer: treeSanitizer);
 
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index a563c05..4c31efb 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -255,7 +255,7 @@
     }
 
     // Assume anything else is already a valid Dart object, either by having
-    // already been processed, or e.g. a clonable native class.
+    // already been processed, or e.g. a cloneable native class.
     return e;
   }
 
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index d7c7ff7..a4751ef 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -92,6 +92,11 @@
    * the [socket] will be used. The [host] can be either a [String] or
    * an [InternetAddress].
    *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
    * Calling this function will _not_ cause a DNS host lookup. If the
    * [host] passed is a [String] the [InternetAddress] for the
    * resulting [SecureSocket] will have the passed in [host] as its
@@ -104,14 +109,16 @@
   static Future<SecureSocket> secure(Socket socket,
       {host,
       SecurityContext context,
-      bool onBadCertificate(X509Certificate certificate)}) {
+      bool onBadCertificate(X509Certificate certificate),
+      @Since("2.6") List<String> supportedProtocols}) {
     return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
         .then<RawSecureSocket>((detachedRaw) {
       return RawSecureSocket.secure(detachedRaw[0] as RawSocket,
           subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
           host: host,
           context: context,
-          onBadCertificate: onBadCertificate);
+          onBadCertificate: onBadCertificate,
+          supportedProtocols: supportedProtocols);
     }).then<SecureSocket>((raw) => new SecureSocket._(raw));
   }
 
@@ -272,6 +279,11 @@
    * the [socket] will be used. The [host] can be either a [String] or
    * an [InternetAddress].
    *
+   * [supportedProtocols] is an optional list of protocols (in decreasing
+   * order of preference) to use during the ALPN protocol negotiation with the
+   * server.  Example values are "http/1.1" or "h2".  The selected protocol
+   * can be obtained via [SecureSocket.selectedProtocol].
+   *
    * Calling this function will _not_ cause a DNS host lookup. If the
    * [host] passed is a [String] the [InternetAddress] for the
    * resulting [SecureSocket] will have this passed in [host] as its
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 4bf7129..663991f 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -71,6 +71,12 @@
         ],
         "uri": "ffi/ffi.dart"
       },
+      "wasm": {
+        "patches": [
+          "../../runtime/lib/wasm_patch.dart"
+        ],
+        "uri": "wasm/wasm.dart"
+      },
       "typed_data": {
         "patches": "../../runtime/lib/typed_data_patch.dart",
         "uri": "typed_data/typed_data.dart"
@@ -481,4 +487,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index 01144b8..f33a42b 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -94,6 +94,11 @@
         - "../../runtime/lib/ffi_dynamic_library_patch.dart"
         - "../../runtime/lib/ffi_native_type_patch.dart"
 
+    wasm:
+      uri: "wasm/wasm.dart"
+      patches:
+        - "../../runtime/lib/wasm_patch.dart"
+
     _http:
       uri: "_http/http.dart"
 
diff --git a/sdk/lib/wasm/wasm.dart b/sdk/lib/wasm/wasm.dart
new file mode 100644
index 0000000..edf0887
--- /dev/null
+++ b/sdk/lib/wasm/wasm.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// {@category VM}
+/// {@nodoc}
+library dart.wasm;
+
+int callWasm(String name, int arg) {
+  return _callWasm(name, arg);
+}
+
+external int _callWasm(String name, int arg);
diff --git a/sdk/lib/wasm/wasm_sources.gni b/sdk/lib/wasm/wasm_sources.gni
new file mode 100644
index 0000000..dcd359a
--- /dev/null
+++ b/sdk/lib/wasm/wasm_sources.gni
@@ -0,0 +1,7 @@
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+wasm_sdk_sources = [
+  "wasm.dart",
+]
diff --git a/tests/co19_2/co19_2-analyzer.status b/tests/co19_2/co19_2-analyzer.status
deleted file mode 100644
index 8841e40..0000000
--- a/tests/co19_2/co19_2-analyzer.status
+++ /dev/null
@@ -1,206 +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.
-
-[ $compiler == dart2analyzer ]
-Language/Classes/Abstract_Instance_Members/override_default_value_t01: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t02: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t03: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t04: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t05: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Getters/type_object_t01: CompileTimeError # Issue 33995
-Language/Classes/Getters/type_object_t02: CompileTimeError # Issue 33995
-Language/Classes/Instance_Methods/Operators/allowed_names_t01: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/Operators/allowed_names_t23: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/Operators/arity_1_t19: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/override_different_default_values_t01: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Instance_Methods/override_different_default_values_t02: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Static_Methods/same_name_method_and_setter_t01: CompileTimeError # Invalid test, see #33237
-Language/Classes/method_definition_t06: MissingCompileTimeError # Please triage this failure
-Language/Enums/syntax_t08: CompileTimeError # Issue 33995
-Language/Enums/syntax_t09: CompileTimeError # Issue 33995
-Language/Errors_and_Warnings/static_warning_t01: CompileTimeError # issue #34319
-Language/Expressions/Assignment/Compound_Assignment/expression_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/indexed_expression_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_static_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/setter_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/variable_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Bitwise_Expressions/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Constants/bitwise_operators_t01: CompileTimeError # triple shift
-Language/Expressions/Constants/constant_list_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Constants/constant_map_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Equality/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t05: CompileTimeError # Please triage this failure
-Language/Expressions/Function_Invocation/async_cleanup_t01: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t02: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t03: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t04: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t05: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t06: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t07: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t08: CompileTimeError # Issue 33995
-Language/Expressions/Identifier_Reference/evaluation_library_or_getter_t01: StaticWarning # Please triage this failure
-Language/Expressions/Instance_Creation/Const/arguments_t03: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/Const/parameterized_type_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/Const/parameterized_type_t02: CompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/New/syntax_t04: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Lists/constant_list_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Lists/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Maps/constant_map_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Maps/constant_map_type_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Maps/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Relational_Expressions/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Shift/allowed_characters_t02: CompileTimeError # triple shift
-Language/Expressions/Shift/integer_t03: CompileTimeError # triple shift
-Language/Expressions/Shift/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Shift/syntax_t15: CompileTimeError # triple shift
-Language/Expressions/Strings/String_Interpolation/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Symbols/syntax_t02: CompileTimeError # triple shift
-Language/Expressions/parentheses_t01: CompileTimeError # triple shift
-Language/Functions/generator_return_type_t02: MissingCompileTimeError # Issue 32192
-Language/Functions/generator_return_type_t06: MissingCompileTimeError # Issue 32192
-Language/Functions/syntax_t03: CompileTimeError # triple shift
-Language/Generics/scope_t03: CompileTimeError # Please triage this failure
-Language/Generics/syntax_t02: CompileTimeError # Please triage this failure
-Language/Generics/syntax_t03: Crash # Issue 29388
-Language/Generics/syntax_t04: CompileTimeError # Bad test
-Language/Libraries_and_Scripts/Exports/implicit_hide_t01: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Imports/implicit_hide_t01: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Imports/implicit_hide_t02: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Parts/compilation_t01: MissingCompileTimeError, Pass # Please triage this failure
-Language/Libraries_and_Scripts/Parts/compilation_t04: Pass, CompileTimeError, MissingCompileTimeError # Please triage this failure
-Language/Libraries_and_Scripts/Parts/compilation_t15: CompileTimeError, Pass # Please triage this failure
-Language/Mixins/Mixin_Application/static_warning_t02: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t11: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t12: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t13: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t14: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t22: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t23: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t24: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t25: CompileTimeError # Issue 26409
-Language/Mixins/declaring_constructor_t05: MissingCompileTimeError # Issue 24767
-Language/Mixins/declaring_constructor_t06: MissingCompileTimeError # Issue 24767
-Language/Reference/Operator_Precedence/precedence_01_assignment_t14: CompileTimeError # triple shift
-Language/Reference/Operator_Precedence/precedence_12_Shift_t04: CompileTimeError # triple shift
-Language/Reference/Operator_Precedence/precedence_t05: CompileTimeError # triple shift
-Language/Statements/Continue/async_loops_t01: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t02: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t03: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t04: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t05: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t06: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t07: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t08: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t09: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t10: CompileTimeError # Issue 33995
-Language/Statements/Continue/control_transfer_t08: CompileTimeError # Issue 33995
-Language/Statements/Continue/control_transfer_t09: CompileTimeError # Issue 33995
-Language/Statements/Expression_Statements/syntax_t06: CompileTimeError # triple shift
-Language/Statements/Return/many_return_statements_t01: CompileTimeError # co19 issue 157
-Language/Statements/Return/many_return_statements_t02: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t01: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t02: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t03: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t04: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t05: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t07: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t08: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t09: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t10: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t11: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t16: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_not_function_t01: CompileTimeError # issue #34319
-Language/Types/Interface_Types/subtype_t30: CompileTimeError # Please triage this failure
-LanguageFeatures/Constant_update2018/CastOperator_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A03_t01/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A03_t02/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t04: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t07: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l1_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t03: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l3_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l1_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t03/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t08/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l3_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l4_t01/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/05: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/06: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/07: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t07/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/05: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/06: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/07: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t01/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Set-literals/constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/constant_set_literals_A03_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/constant_set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/exact_types_of_literals_A01_t03: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/semantics_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/syntax_compatibility_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Simple-bounds/static/typedef_l2_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t02: CompileTimeError # Issue 32903
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t05: CompileTimeError # Issue 32903
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t08: CompileTimeError # Issue 32903
-LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
-LanguageFeatures/regression/33597_t01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/regression/33701_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t01: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t03: CompileTimeError # Please triage this failure
-LibTest/async/Future/Future_A01_t01: CompileTimeError # Please triage this failure
-
-[ $compiler == dart2analyzer && $system != macos && $system != windows ]
-LanguageFeatures/regression/33585_t01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/regression/33585_t02: MissingCompileTimeError # Please triage this failure
-
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 7bd5ada..e6024bc 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -18,29 +18,15 @@
 LanguageFeatures/Constant-update-2018/NewOperators_A01_t06/none: Crash
 
 [ $runtime == vm ]
-LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Slow # Does many calls
-LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Slow # Does many calls
-LibTest/core/List/List_class_A01_t02: Pass, Slow # Does many calls
-LibTest/io/FileSystemCreateEvent/isDirectory_A01_t06: Pass, RuntimeError # https://github.com/dart-lang/co19/issues/186
+LibTest/collection/ListBase/ListBase_class_A01_t02: Slow # Does many calls
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Slow # Does many calls
+LibTest/core/List/List_class_A01_t02: Slow # Does many calls
 LibTest/io/RawDatagramSocket/*: Skip # RawDatagramSocket are flacky. Skip them all until rewritten
-LibTest/io/RawDatagramSocket/any_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/any_A01_t03: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/asBroadcastStream_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/distinct_A01_t05: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/lastWhere_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/listen_A02_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/receive_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/timeout_A02_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/timeout_A06_t01: Pass, Fail # Next roll might fix it (see https://github.com/dart-lang/co19/commit/8b2e2be5bc3bb9fec41efec8ac6fc777e231d915)
-LibTest/io/RawDatagramSocket/where_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
 
 [ $fasta ]
 Language/Classes/Instance_Methods/Operators/allowed_names_t01: Skip # triple-shift flag
 Language/Classes/Instance_Methods/Operators/allowed_names_t23: Skip # triple-shift flag
 Language/Classes/Instance_Methods/Operators/arity_1_t19: Skip # triple-shift flag
-Language/Classes/Superclasses/wrong_superclass_t08: MissingCompileTimeError # Issue 30273
-Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError # Issue 30273
-Language/Classes/method_definition_t06: MissingCompileTimeError # Legal
 Language/Enums/restrictions_t10: Crash
 Language/Expressions/Assignment/Compound_Assignment/expression_assignment_t12: Skip # triple-shift flag
 Language/Expressions/Assignment/Compound_Assignment/indexed_expression_assignment_t12: Skip # triple-shift flag
@@ -52,13 +38,8 @@
 Language/Expressions/Constants/bitwise_operators_t01: Skip # triple-shift flag
 Language/Expressions/Constants/bitwise_operators_t07: Skip # triple-shift flag
 Language/Expressions/Constants/bitwise_operators_t08: Skip # triple-shift flag
-Language/Expressions/Constants/constant_list_t02: MissingCompileTimeError # Legal because of implicit const
-Language/Expressions/Constants/constant_map_t02: MissingCompileTimeError # Legal because of implicit const
 Language/Expressions/Equality/syntax_t01: Skip # triple-shift flag
-Language/Expressions/Instance_Creation/Const/arguments_t03: MissingCompileTimeError # Legal because of implicit const
-Language/Expressions/Instance_Creation/New/syntax_t04: MissingCompileTimeError # Legal because of implicit new
 Language/Expressions/Lists/syntax_t01: Skip # triple-shift flag
-Language/Expressions/Maps/key_value_equals_operator_t01: MissingCompileTimeError # Issue 32557
 Language/Expressions/Maps/syntax_t01: Skip # triple-shift flag
 Language/Expressions/Relational_Expressions/syntax_t01: Skip # triple-shift experiment flag
 Language/Expressions/Shift/allowed_characters_t02: Skip # triple-shift flag
@@ -89,7 +70,6 @@
 Language/Expressions/Symbols/syntax_t02: Skip # triple-shift experiment flag
 Language/Expressions/parentheses_t01: Skip # triple-shift experiment flag
 Language/Functions/syntax_t03: Skip # triple-shift experiment flag
-Language/Libraries_and_Scripts/Imports/library_name_t01: MissingCompileTimeError # Expects an error, but this is a warning in Dart 2
 Language/Mixins/Mixin_Application/abstract_t09: Crash
 Language/Mixins/Mixin_Application/abstract_t10: Crash
 Language/Mixins/Mixin_Application/abstract_t11: Crash
@@ -103,7 +83,6 @@
 Language/Mixins/Mixin_Application/initializers_t06: Crash
 Language/Mixins/Mixin_Application/interfaces_t06: Crash
 Language/Mixins/Mixin_Application/interfaces_t07: Crash
-Language/Mixins/Mixin_Application/static_warning_t01: MissingCompileTimeError # Mixin super equirement
 Language/Mixins/Mixin_Application/superclass_t03: Crash
 Language/Mixins/Mixin_Application/superclass_t04: Crash
 Language/Mixins/Mixin_Application/superinterfaces_t10: Crash
@@ -114,13 +93,10 @@
 Language/Mixins/Mixin_Application/warning_t04: Crash
 Language/Mixins/Mixin_Application/wrong_mixin_type_t09: Crash
 Language/Mixins/Mixin_Composition/order_t02: Crash
-Language/Mixins/declaring_constructor_t05: MissingCompileTimeError # Mixin constructor
-Language/Mixins/declaring_constructor_t06: MissingCompileTimeError # Mixin constructor
 Language/Mixins/declaring_constructor_t11: Crash
 Language/Reference/Operator_Precedence/precedence_01_assignment_t14: Skip # triple-shift experimental flag
 Language/Reference/Operator_Precedence/precedence_12_Shift_t04: Skip # triple-shift experimental flag
 Language/Reference/Operator_Precedence/precedence_t05: Skip # triple-shift experimental flag
-Language/Statements/Continue/label_t07: MissingCompileTimeError # Issue 34206
 Language/Statements/Expression_Statements/syntax_t06: Skip # triple-shift experimental flag
 LanguageFeatures/Constant-update-2018/NewOperators_A01_t01: Crash
 LanguageFeatures/Constant-update-2018/NewOperators_A01_t02: Crash
@@ -199,9 +175,6 @@
 LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/02: Crash
 LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/none: Crash
 LanguageFeatures/Set-literals/disambiguating_A02_t03: Crash
-LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
 LanguageFeatures/regression/34803_t01: Crash
 LanguageFeatures/regression/34803_t02: Crash
 
@@ -214,19 +187,8 @@
 LanguageFeatures/Subtyping/static/generated/function_type_function_arguments_binding_A04_t02: Crash
 
 [ $arch == simdbc64 && ($compiler == dartk || $compiler == dartkb) ]
-LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout, Pass # https://github.com/dart-lang/sdk/issues/35316 as well?
-LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout, Pass # https://github.com/dart-lang/sdk/issues/35316 as well?
 LibTest/isolate/Isolate/removeErrorListener_A02_t01: Crash
 
-[ $compiler != dart2js && $runtime != vm && $fasta ]
-Language/Classes/Constructors/Constant_Constructors/invalid_constant_initializer_t02: MissingCompileTimeError # Issue 34192
-Language/Expressions/Instance_Creation/Const/exception_t01: MissingCompileTimeError # Issue 31936
-Language/Metadata/compilation_t03: MissingCompileTimeError # Issue 34205
-
-[ $compiler != dart2js && $fasta ]
-Language/Statements/Switch/equal_operator_t01: MissingCompileTimeError # Issue 32557
-Language/Statements/Switch/equal_operator_t02: MissingCompileTimeError # Issue 32557
-
 [ $runtime == vm && $system == linux && ($compiler == dartk || $compiler == dartkb) ]
 LibTest/isolate/Isolate/spawn_A06_t03: Crash
 
@@ -238,9 +200,6 @@
 LibTest/core/List/List_class_A01_t02: Slow
 LibTest/core/List/List_class_A01_t03: Slow
 
-[ $runtime != vm && $fasta ]
-Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: MissingCompileTimeError # Issue 34192
-
 [ $runtime != vm && ($compiler == dartk || $compiler == dartkb) ]
 Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: Crash
 
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 17a3670..9afaf8b 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -2,71 +2,71 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-analyses/analyze_test: Slow, Pass
-analyses/api_dynamic_test: Slow, Pass
-analyses/dart2js_dynamic_test: Slow, Pass
-closure/closure_test: Pass, Slow
+analyses/analyze_test: Slow
+analyses/api_dynamic_test: Slow
+analyses/dart2js_dynamic_test: Slow
+closure/closure_test: Slow
 codegen/gvn_dynamic_field_get_test: Fail # Issue 18519
 codegen/list_tracer_length_test: Fail # Issue 33051
-codegen/load_elimination_test: Pass, Slow
+codegen/load_elimination_test: Slow
 codegen/logical_expression_test: Fail # Issue 17027
-codegen/model_test: Pass, Slow
+codegen/model_test: Slow
 codegen/side_effect_tdiv_regression_test: Fail # Issue 33050
 codegen/simple_function_subtype_test: Fail # simple_function_subtype_test is temporarily(?) disabled due to new method for building function type tests.
-deferred_loading/deferred_loading_test: Slow, Pass
-end_to_end/dump_info_test: Slow, Pass
+deferred_loading/deferred_loading_test: Slow
+end_to_end/dump_info_test: Slow
 end_to_end/generate_code_with_compile_time_errors_test: RuntimeError # not supported yet with the new FE.
 end_to_end/show_package_warnings_test: RuntimeError # missing errors from the FE
-equivalence/id_equivalence1_test: Pass, Slow
-equivalence/id_equivalence2_test: Pass, Slow
-impact/impact_test: Pass, Slow
-inference/inference0_test: Slow, Pass
-inference/inference1_test: Slow, Pass
-inference/inference2_test: Slow, Pass
-inference/inference3_test: Slow, Pass
+equivalence/id_equivalence1_test: Slow
+equivalence/id_equivalence2_test: Slow
+impact/impact_test: Slow
+inference/inference0_test: Slow
+inference/inference1_test: Slow
+inference/inference2_test: Slow
+inference/inference3_test: Slow
 inference/simple_inferrer_const_closure2_test: Fail # Issue 16507
 inference/simple_inferrer_const_closure_test: Fail # Issue 16507
 inference/simple_inferrer_global_field_closure_test: Fail # Issue 16507
 inference/swarm_test: Slow, Pass, Fail #
-inlining/inlining_test: Slow, Pass
-model/native_test: Pass, Slow
-model/no_such_method_enabled_test: Pass, Slow
-model/subtype_test: Pass, Slow
-modular/*: Slow, Pass
+inlining/inlining_test: Slow
+model/native_test: Slow
+model/no_such_method_enabled_test: Slow
+model/subtype_test: Slow
+modular/*: Slow
 packages/*: Skip # Skip packages folder
-rti/rti_emission_test: Pass, Slow
-rti/rti_need0_test: Pass, Slow
-rti/rti_need1_test: Pass, Slow
-serialization/serialization_test: Pass, Slow
+rti/rti_emission_test: Slow
+rti/rti_need0_test: Slow
+rti/rti_need1_test: Slow
+serialization/serialization_test: Slow
 sourcemaps/d2js_validity_test: RuntimeError # Issue 33072
 sourcemaps/deferred_d2js_validity_test: RuntimeError # Issue 33072
-sourcemaps/source_mapping_invokes_test: Pass, Slow
-sourcemaps/source_mapping_operators_test: Pass, Slow
-sourcemaps/source_mapping_test: Pass, Slow
-sourcemaps/stacktrace_test: Pass, Slow
+sourcemaps/source_mapping_invokes_test: Slow
+sourcemaps/source_mapping_operators_test: Slow
+sourcemaps/source_mapping_test: Slow
+sourcemaps/stacktrace_test: Slow
 
 [ $mode == debug ]
-deferred/load_graph_segmentation_test: Pass, Slow
-deferred/load_mapping_test: Pass, Slow
-end_to_end/dart2js_batch_test: Pass, Slow
-end_to_end/exit_code_test: Pass, Slow
-end_to_end/in_user_code_test: Pass, Slow
-end_to_end/show_package_warnings_test: Pass, Slow
+deferred/load_graph_segmentation_test: Slow
+deferred/load_mapping_test: Slow
+end_to_end/dart2js_batch_test: Slow
+end_to_end/exit_code_test: Slow
+end_to_end/in_user_code_test: Slow
+end_to_end/show_package_warnings_test: Slow
 
 [ $checked ]
-codegen/value_range_kernel_test: Pass, Slow
-codegen/value_range_test: Pass, Slow
-end_to_end/exit_code_test: Pass, Slow
-end_to_end/output_type_test: Pass, Slow
-end_to_end/uri_retention_test: Pass, Slow
-jsinterop/declaration_test: Slow, Pass
-jsinterop/interop_anonymous_unreachable_test: Pass, Slow
-jsinterop/world_test: Pass, Slow
-sourcemaps/stacktrace_test: Pass, Slow
+codegen/value_range_kernel_test: Slow
+codegen/value_range_test: Slow
+end_to_end/exit_code_test: Slow
+end_to_end/output_type_test: Slow
+end_to_end/uri_retention_test: Slow
+jsinterop/declaration_test: Slow
+jsinterop/interop_anonymous_unreachable_test: Slow
+jsinterop/world_test: Slow
+sourcemaps/stacktrace_test: Slow
 
 [ !$checked ]
 end_to_end/exit_code_test: Skip # This tests requires checked mode.
-jsinterop/declaration_test: Slow, Pass
+jsinterop/declaration_test: Slow
 
 [ $runtime == chrome || $runtime == ff || $runtime == firefox || $runtime == safari || $jscl ]
 *: Skip # dart2js uses #import('dart:io'); and it is not self-hosted (yet).
diff --git a/tests/compiler/dart2js/end_to_end/no_platform_test.dart b/tests/compiler/dart2js/end_to_end/no_platform_test.dart
index c6c11da..968507b 100644
--- a/tests/compiler/dart2js/end_to_end/no_platform_test.dart
+++ b/tests/compiler/dart2js/end_to_end/no_platform_test.dart
@@ -36,7 +36,6 @@
 
   asyncTest(() async {
     await runTest(const {});
-    await runTest(const {fe.ExperimentalFlag.constantUpdate2018: true});
-    await runTest(const {fe.ExperimentalFlag.spreadCollections: true});
+    await runTest(const {fe.ExperimentalFlag.extensionMethods: true});
   });
 }
diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
index 54eeeac..4455bf5 100644
--- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
+++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
@@ -429,7 +429,6 @@
 
     if (setUpFunction != null) setUpFunction();
 
-    print('name="${name}"');
     if (skip.contains(name)) {
       print('--skipped ------------------------------------------------------');
     } else {
diff --git a/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart b/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart
new file mode 100644
index 0000000..eab4fd4
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart
@@ -0,0 +1,51 @@
+// 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.
+
+@JS()
+library main;
+
+import 'dart:html' show File;
+
+import 'package:js/js.dart';
+
+/*member: foo=:
+ type=[
+  inst:JSBool,
+  native:ApplicationCacheErrorEvent,
+  native:DomError,
+  native:DomException,
+  native:ErrorEvent,
+  native:MediaError,
+  native:NavigatorUserMediaError,
+  native:OverconstrainedError,
+  native:PositionError,
+  native:SensorErrorEvent,
+  native:SpeechRecognitionError,
+  native:SqlError,
+  param:Function]
+ */
+@JS()
+external set foo(Function f);
+
+/*member: _doStuff:
+ dynamic=[File.==,File.name],
+ static=[defineProperty(3),print(1)],
+ type=[inst:JSBool,inst:JSNull,inst:JSString,param:File,param:String]
+*/
+void _doStuff(String name, File file) {
+  if (file == null) {
+    print('OK');
+  }
+  print(file.name);
+}
+
+/*member: main:
+ static=[
+ _doStuff,
+ allowInterop<Function>(1),
+ set:foo]
+*/
+void main() {
+  foo = allowInterop(_doStuff);
+}
diff --git a/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart b/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart
new file mode 100644
index 0000000..0dbb322
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library main;
+
+import 'dart:html' show File;
+
+import 'package:js/js.dart';
+
+/*member: foo=:
+ static=[
+  checkSubtype(4),
+  getRuntimeTypeArgument(3),
+  getRuntimeTypeArgumentIntercepted(4),
+  getRuntimeTypeInfo(1),
+  getTypeArgumentByIndex(2),
+  setRuntimeTypeInfo(2)],
+ type=[
+  inst:JSArray<dynamic>,
+  inst:JSBool,
+  inst:JSExtendableArray<dynamic>,
+  inst:JSFixedArray<dynamic>,
+  inst:JSMutableArray<dynamic>,
+  inst:JSUnmodifiableArray<dynamic>,
+  native:ApplicationCacheErrorEvent,
+  native:DomError,
+  native:DomException,
+  native:ErrorEvent,
+  native:File,
+  native:MediaError,
+  native:NavigatorUserMediaError,
+  native:OverconstrainedError,
+  native:PositionError,
+  native:SensorErrorEvent,
+  native:SpeechRecognitionError,
+  native:SqlError,
+  param:void Function(String,File)]
+*/
+@JS()
+external set foo(void Function(String, File) f);
+
+/*member: _doStuff:
+ dynamic=[File.==,File.name],
+ static=[defineProperty(3),print(1)],
+ type=[inst:JSBool,inst:JSNull,inst:JSString,param:File,param:String]
+*/
+void _doStuff(String name, File file) {
+  if (file == null) {
+    print('OK');
+  }
+  print(file.name);
+}
+
+/*member: main:
+ static=[
+  _doStuff,
+  allowInterop<void Function(String,File)>(1),
+  set:foo]
+*/
+void main() {
+  foo = allowInterop(_doStuff);
+}
diff --git a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
index 5dabc0f..180375b 100644
--- a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
+++ b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
@@ -600,7 +600,9 @@
                   (ir.LocatedMessage message, List<ir.LocatedMessage> context) {
             // TODO(johnniwinther): Assert that `message.uri != null`. Currently
             // all unevaluated constants have no uri.
-            errors.add(message.code.name);
+            // The actual message is a "constant errors starts here" message,
+            // the "real error message" is the first in the context.
+            errors.add(context.first.code.name);
             reportLocatedMessage(elementMap.reporter, message, context);
           }, environment: environment, supportReevaluationForTesting: true);
           ir.Constant evaluatedConstant = evaluator.evaluate(initializer);
diff --git a/tests/compiler/dart2js_extra/37576_test.dart b/tests/compiler/dart2js_extra/37576_test.dart
new file mode 100644
index 0000000..b243963
--- /dev/null
+++ b/tests/compiler/dart2js_extra/37576_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:js/js.dart';
+
+@JS('jsFun')
+external set jsFun(Function fun);
+
+void main() {
+  jsFun = allowInterop(dartFun);
+}
+
+void dartFun() {}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index b1acb29..efc2aea 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -3,16 +3,8 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js ]
-23264_test: RuntimeError
-bound_closure_interceptor_type_test: RuntimeError
 bounds_check4a_test: RuntimeError # Issue 32741
 bounds_check4b_test: RuntimeError # Issue 32741
-class_test: Fail
-closure_capture2_test: RuntimeError
-constant_javascript_semantics4_test: Fail, OK
-constant_javascript_semantics_test/03: CompileTimeError
-constant_javascript_semantics_test/04: CompileTimeError
-constant_javascript_semantics_test/none: CompileTimeError
 generic_class_is_test: Fail # Issue 32004
 jsinterop_test/01: MissingCompileTimeError # Issue 34174
 jsinterop_test/02: MissingCompileTimeError # Issue 34174
@@ -52,17 +44,6 @@
 non_jsinterop_test/52: MissingCompileTimeError # Issue 34345
 non_jsinterop_test/53: MissingCompileTimeError # Issue 34345
 non_jsinterop_test/54: MissingCompileTimeError # Issue 34345
-private_symbol_literal_test/01: MissingCompileTimeError
-private_symbol_literal_test/02: MissingCompileTimeError
-private_symbol_literal_test/03: MissingCompileTimeError
-private_symbol_literal_test/04: MissingCompileTimeError
-private_symbol_literal_test/05: MissingCompileTimeError
-private_symbol_literal_test/06: MissingCompileTimeError
-regress/4562_test/none: CompileTimeError
-round_constant_folding_test: CompileTimeError
-statements_test: Fail
-type_constant_switch_test/01: MissingCompileTimeError
-typed_locals_test: Pass, Fail
 
 [ $compiler != dart2js ]
 dummy_compiler_test: SkipByDesign # Issue 30773. Test should be migrated as a unit test of dart2js, is only intended to test self-hosting.
@@ -100,11 +81,6 @@
 [ $compiler == dart2js && $runtime == none ]
 *: Fail, Pass # TODO(ahe): Triage these tests.
 
-[ $compiler == dart2js && $checked ]
-dummy_compiler_test: Crash
-local_signature_test: Crash
-minus_zero_test/01: MissingCompileTimeError
-
 [ $compiler == dart2js && $csp ]
 deferred_custom_loader_test: SkipByDesign # Issue 25683
 deferred_fail_and_retry_test: SkipByDesign # Uses eval to simulate failed loading.
@@ -118,9 +94,7 @@
 closure_capture2_test: Pass # Passes for the wrong reason
 code_motion_exception_test: Skip # Requires unminified operator names.
 deferred/reflect_multiple_annotations_test: Crash # NoSuchMethodError: The getter 'closureClassEntity' was called on null.
-deferred/reflect_multiple_annotations_test: Fail
 deferred/reflect_multiple_default_arg_test: Crash # NoSuchMethodError: The getter 'closureClassEntity' was called on null.
-deferred/reflect_multiple_default_arg_test: Fail
 mirrors_used_warning_test/minif: Fail, OK # Tests warning that minified code will be broken.
 runtime_type_test: Fail, OK # Tests extected output of Type.toString().
 to_string_test: Fail # Issue 7179.
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 0d9594f..ad3e21a 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -3,20 +3,14 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js ]
-bound_closure_super_test: RuntimeError
 fake_thing_test: RuntimeError # Issue 13010
 field_type2_test: CompileTimeError # Issue 33762
 field_type_test: CompileTimeError # Issue 33762
 native_exceptions1_frog_test: CompileTimeError # Issue 33762
-native_library_same_name_used_frog_test: CompileTimeError
 native_mixin_with_plain_test: CompileTimeError # Issue 33762
 native_window1_frog_test: CompileTimeError # Issue 33762
 native_window2_frog_test: CompileTimeError # Issue 33762
 subclassing_constructor_1_test: CompileTimeError # Issue 33762
-subclassing_constructor_1_test: RuntimeError
-subclassing_super_call_test: RuntimeError
-subclassing_super_field_1_test: RuntimeError
-subclassing_super_field_2_test: RuntimeError
 
 [ $browser ]
 *: Skip
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 4d9dd1d..04290fc 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -163,9 +163,6 @@
 symbol_test/none: RuntimeError # Issues 11669 and 31936 - throwing const constructors.
 unicode_test: RuntimeError # Issue 18061: German double S.
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
 [ ($arch == simdbc || $arch == simdbc64) && ($hot_reload || $hot_reload_rollback) ]
 uri_parse_test: SkipSlow
 
diff --git a/tests/corelib_2/unsigned_shift_test.dart b/tests/corelib_2/unsigned_shift_test.dart
index 09687f8..457bc7c 100644
--- a/tests/corelib_2/unsigned_shift_test.dart
+++ b/tests/corelib_2/unsigned_shift_test.dart
@@ -44,7 +44,7 @@
   }
 }
 
-void testNonDoublesShift() {
+void testNonDoubleShifts() {
   double n = 0.0;
   n >>> 1; //# 01: compile-time error
   for (dynamic number in [0.0, 1.0, 2.4, -2.4, double.infinity, double.nan]) {
@@ -60,25 +60,25 @@
   // >>> is a constant operation on integers.
   const c1 = 2 >>> 1;
   const c2 = (1 >>> 0) >>> 0;
-  // >> is a potentially constant operation independent of type.
+  // >>> is a potentially constant operation independent of type.
   // The type must still type-check.
   const c3 = false ? 1 : c >>> c;
-  const c4 = true || c >>> c;
 
   // It's an error if it doesn't type-check.
-  const c5 = true || "string" >>> 1;  //# 02: compile-time error
+  const c4 = true || c >>> c; //# 02: compile-time error
+  const c5 = true || "string" >>> 1;  //# 03: compile-time error
 
   // Or if the shift isn't on integers and it is evaluated.
-  const c6 = c >>> c; //# 03: compile-time error
+  const c6 = c >>> c; //# 04: compile-time error
 
   // Or if shifting throws
-  const c7 = 1 >>> -1; //# 04: compile-time error
-  const c8 = 1 >>> 65; //# 05: compile-time error
+  const c7 = 1 >>> -1; //# 05: compile-time error
+  const c8 = 1 >>> 65; //# 06: compile-time error
 
-  Expect.notNull(c1 + c2 + c3 + c4);  // Avoid "unused variable" warnings.
+  Expect.isNotNull(c1 + c2 + c3);  // Avoid "unused variable" warnings.
 }
 
-const bool isJSBitOps => (-1 | 0) > 0;
+const bool isJSBitOps = (-1 | 0) > 0;
 const String jsFlag = isJSBitOps ? " (JS)" : "";
 
 void testShift(int value, int shift) {
@@ -94,7 +94,7 @@
     return;
   }
   var expected;
-  if (isJsBitOps) {
+  if (isJSBitOps) {
     // TODO: Check that this is the desired behavior for JS >>>.
     expected = value.toUnsigned(32) >> shift;
   } else if (value < 0) {
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 7652349..46f4755 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -2,33 +2,32 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-[ $arch == simdbc ]
-*: Skip # FFI not yet supported on SimDBC32: dartbug.com/36809
+[ $arch == simdbc || $arch == simdbc64 ]
+*: Skip # SIMDBC will be deleted soon.
 
-[ $arch == simdbc64 ]
-function_callbacks_test: Skip # Issue 37140
-regress_37511_callbacks_test: Skip # Issue 37140
+# Issue 37295, not yet supported in blobs snapshots at present.
+[ $compiler == dartkp && $system == windows ]
+function_callbacks_test: Skip
+regress_37511_callbacks_test: Skip
+stacktrace_regress_37910_test: Skip
+
+[ $compiler != dartkp || $system != windows ]
+function_callbacks_unsupported_test: SkipByDesign # See above
 
 [ $builder_tag == asan ]
 data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose.
 
-# These tests trigger and catch an abort (intentionally) and terminate the VM
-# before it can generate a snapshot.
-[ $compiler == app_jitk ]
+# These tests trigger and catch an abort (intentionally) and terminate the VM.
+# They're incompatible with ASAN because not all memory is freed when aborting and
+# with AppJit because the abort the VM before it can generate a snapshot.
+[ $compiler == app_jitk || $builder_tag == asan ]
 function_callbacks_test/01: Skip
 function_callbacks_test/02: Skip
 function_callbacks_test/03: Skip
 
-[ $runtime == dart_precompiled ]
-function_callbacks_test: Skip  # Issue dartbug.com/37295
-regress_37511_callbacks_test: Skip  # Issue dartbug.com/37295
-
 [ $arch == arm && $system != android ]
 *: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309
 
-[ $arch == simdbc64 && $system != linux && $system != macos ]
-*: Skip # DBC is only supported on MacOS and Linux for testing
-
 [ $runtime != dart_precompiled && $runtime != vm ]
 *: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
 
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index 4377938..1c5eca5 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -5,7 +5,9 @@
 // Dart test program for testing dart:ffi function pointers with callbacks.
 //
 // VMOptions=--enable-testing-pragmas
+// VMOptions=--enable-testing-pragmas --stacktrace-every=100
 // VMOptions=--enable-testing-pragmas --write-protect-code --no-dual-map-code
+// VMOptions=--enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100
 // SharedObjects=ffi_test_functions
 
 library FfiTest;
@@ -190,26 +192,26 @@
   Test("ManyInts", Pointer.fromFunction<ManyIntsType>(manyInts, 0)),
   Test("ManyDoubles", Pointer.fromFunction<ManyDoublesType>(manyDoubles, 0.0)),
   Test("ManyArgs", Pointer.fromFunction<ManyArgsType>(manyArgs, 0.0)),
-  Test("Store", Pointer.fromFunction<StoreType>(store, null)),
-  Test("NullPointers", Pointer.fromFunction<NullPointersType>(nullPointers, null)),
+  Test("Store", Pointer.fromFunction<StoreType>(store)),
+  Test("NullPointers", Pointer.fromFunction<NullPointersType>(nullPointers)),
   Test("ReturnNull", Pointer.fromFunction<ReturnNullType>(returnNull, 42)),
-  Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid, null)),
+  Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid)),
   Test("ThrowExceptionDouble",
       Pointer.fromFunction<ThrowExceptionDouble>(throwExceptionDouble, 42.0)),
   Test(
       "ThrowExceptionPointer",
       Pointer.fromFunction<ThrowExceptionPointer>(
-          throwExceptionPointer, Pointer<Void>.fromAddress(42))),
+          throwExceptionPointer)),
   Test("ThrowException", Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
-  Test("GC", Pointer.fromFunction<ReturnVoid>(testGC, null)),
-  Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper, null)),
+  Test("GC", Pointer.fromFunction<ReturnVoid>(testGC)),
+  Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper)),
 ];
 
 testCallbackWrongThread() =>
-    Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid, null)).run();
+    Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid)).run();
 
 testCallbackOutsideIsolate() =>
-    Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid, null))
+    Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid))
         .run();
 
 isolateHelper(int callbackPointer) {
@@ -221,22 +223,25 @@
 }
 
 testCallbackWrongIsolate() async {
-  final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid, null).address;
+  final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid).address;
   final ReceivePort exitPort = ReceivePort();
   await Isolate.spawn(isolateHelper, callbackPointer,
       errorsAreFatal: true, onExit: exitPort.sendPort);
   await exitPort.first;
 }
 
+const double zeroPointZero = 0.0;
+
 // Correct type of exceptionalReturn argument to Pointer.fromFunction.
 double testExceptionalReturn() {
   Pointer.fromFunction<Double Function()>(testExceptionalReturn, 0.0);
-  Expect.throwsArgumentError(() => Pointer.fromFunction<Void Function()>(returnVoid, 0));
-  Pointer.fromFunction<Void Function()>(returnVoid, null);
-  Expect.throwsArgumentError(() => Pointer.fromFunction<Double Function()>(returnVoid, null));
+  Pointer.fromFunction<Double Function()>(testExceptionalReturn, zeroPointZero);
 
+  Pointer.fromFunction<Double Function()>(returnVoid, null);  //# 59: compile-time error
+  Pointer.fromFunction<Void Function()>(returnVoid, 0);  //# 60: compile-time error
   Pointer.fromFunction<Double Function()>(testExceptionalReturn, "abc");  //# 61: compile-time error
   Pointer.fromFunction<Double Function()>(testExceptionalReturn, 0);  //# 62: compile-time error
+  Pointer.fromFunction<Double Function()>(testExceptionalReturn);  //# 63: compile-time error
 }
 
 void main() async {
@@ -261,11 +266,1014 @@
   // trampolines. The use of distinct exceptional return values forces separate
   // trampolines.
   final List<Pointer> pointers = [];
-  for (int i = 0; i < 1000; ++i) {
-    pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, i));
-  }
+
+  // All the parameters of 'fromFunction' are forced to be constant so that we
+  // only need to generate one trampoline per 'fromFunction' call-site.
+  //
+  // As a consequence, to force the creation of 1000 trampolines (and prevent
+  // any possible caching), we need literally 1000 call-sites.
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 1));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 2));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 3));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 4));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 5));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 6));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 7));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 8));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 9));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 10));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 11));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 12));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 13));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 14));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 15));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 16));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 17));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 18));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 19));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 20));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 21));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 22));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 23));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 24));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 25));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 26));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 27));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 28));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 29));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 30));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 31));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 32));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 33));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 34));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 35));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 36));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 37));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 38));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 39));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 40));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 41));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 42));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 43));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 44));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 45));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 46));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 47));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 48));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 49));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 50));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 51));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 52));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 53));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 54));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 55));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 56));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 57));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 58));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 59));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 60));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 61));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 62));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 63));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 64));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 65));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 66));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 67));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 68));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 69));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 70));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 71));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 72));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 73));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 74));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 75));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 76));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 77));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 78));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 79));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 80));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 81));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 82));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 83));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 84));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 85));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 86));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 87));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 88));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 89));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 90));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 91));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 92));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 93));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 94));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 95));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 96));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 97));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 98));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 99));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 100));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 101));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 102));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 103));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 104));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 105));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 106));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 107));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 108));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 109));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 110));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 111));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 112));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 113));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 114));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 115));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 116));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 117));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 118));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 119));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 120));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 121));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 122));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 123));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 124));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 125));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 126));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 127));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 128));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 129));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 130));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 131));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 132));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 133));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 134));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 135));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 136));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 137));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 138));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 139));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 140));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 141));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 142));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 143));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 144));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 145));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 146));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 147));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 148));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 149));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 150));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 151));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 152));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 153));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 154));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 155));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 156));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 157));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 158));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 159));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 160));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 161));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 162));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 163));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 164));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 165));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 166));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 167));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 168));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 169));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 170));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 171));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 172));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 173));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 174));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 175));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 176));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 177));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 178));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 179));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 180));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 181));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 182));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 183));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 184));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 185));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 186));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 187));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 188));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 189));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 190));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 191));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 192));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 193));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 194));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 195));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 196));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 197));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 198));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 199));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 200));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 201));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 202));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 203));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 204));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 205));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 206));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 207));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 208));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 209));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 210));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 211));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 212));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 213));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 214));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 215));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 216));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 217));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 218));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 219));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 220));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 221));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 222));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 223));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 224));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 225));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 226));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 227));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 228));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 229));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 230));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 231));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 232));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 233));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 234));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 235));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 236));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 237));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 238));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 239));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 240));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 241));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 242));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 243));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 244));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 245));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 246));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 247));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 248));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 249));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 250));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 251));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 252));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 253));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 254));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 255));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 256));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 257));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 258));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 259));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 260));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 261));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 262));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 263));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 264));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 265));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 266));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 267));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 268));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 269));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 270));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 271));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 272));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 273));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 274));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 275));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 276));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 277));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 278));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 279));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 280));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 281));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 282));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 283));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 284));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 285));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 286));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 287));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 288));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 289));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 290));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 291));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 292));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 293));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 294));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 295));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 296));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 297));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 298));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 299));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 300));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 301));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 302));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 303));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 304));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 305));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 306));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 307));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 308));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 309));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 310));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 311));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 312));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 313));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 314));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 315));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 316));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 317));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 318));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 319));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 320));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 321));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 322));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 323));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 324));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 325));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 326));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 327));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 328));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 329));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 330));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 331));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 332));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 333));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 334));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 335));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 336));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 337));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 338));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 339));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 340));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 341));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 342));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 343));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 344));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 345));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 346));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 347));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 348));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 349));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 350));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 351));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 352));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 353));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 354));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 355));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 356));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 357));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 358));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 359));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 360));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 361));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 362));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 363));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 364));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 365));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 366));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 367));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 368));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 369));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 370));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 371));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 372));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 373));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 374));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 375));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 376));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 377));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 378));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 379));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 380));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 381));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 382));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 383));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 384));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 385));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 386));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 387));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 388));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 389));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 390));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 391));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 392));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 393));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 394));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 395));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 396));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 397));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 398));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 399));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 400));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 401));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 402));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 403));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 404));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 405));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 406));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 407));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 408));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 409));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 410));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 411));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 412));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 413));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 414));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 415));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 416));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 417));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 418));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 419));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 420));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 421));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 422));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 423));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 424));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 425));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 426));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 427));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 428));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 429));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 430));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 431));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 432));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 433));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 434));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 435));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 436));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 437));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 438));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 439));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 440));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 441));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 442));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 443));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 444));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 445));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 446));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 447));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 448));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 449));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 450));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 451));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 452));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 453));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 454));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 455));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 456));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 457));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 458));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 459));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 460));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 461));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 462));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 463));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 464));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 465));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 466));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 467));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 468));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 469));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 470));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 471));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 472));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 473));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 474));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 475));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 476));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 477));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 478));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 479));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 480));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 481));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 482));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 483));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 484));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 485));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 486));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 487));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 488));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 489));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 490));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 491));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 492));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 493));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 494));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 495));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 496));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 497));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 498));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 499));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 500));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 501));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 502));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 503));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 504));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 505));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 506));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 507));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 508));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 509));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 510));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 511));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 512));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 513));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 514));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 515));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 516));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 517));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 518));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 519));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 520));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 521));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 522));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 523));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 524));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 525));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 526));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 527));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 528));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 529));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 530));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 531));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 532));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 533));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 534));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 535));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 536));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 537));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 538));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 539));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 540));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 541));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 542));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 543));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 544));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 545));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 546));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 547));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 548));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 549));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 550));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 551));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 552));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 553));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 554));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 555));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 556));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 557));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 558));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 559));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 560));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 561));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 562));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 563));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 564));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 565));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 566));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 567));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 568));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 569));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 570));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 571));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 572));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 573));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 574));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 575));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 576));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 577));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 578));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 579));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 580));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 581));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 582));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 583));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 584));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 585));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 586));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 587));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 588));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 589));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 590));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 591));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 592));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 593));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 594));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 595));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 596));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 597));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 598));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 599));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 600));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 601));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 602));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 603));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 604));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 605));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 606));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 607));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 608));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 609));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 610));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 611));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 612));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 613));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 614));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 615));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 616));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 617));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 618));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 619));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 620));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 621));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 622));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 623));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 624));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 625));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 626));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 627));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 628));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 629));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 630));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 631));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 632));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 633));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 634));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 635));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 636));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 637));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 638));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 639));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 640));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 641));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 642));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 643));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 644));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 645));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 646));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 647));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 648));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 649));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 650));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 651));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 652));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 653));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 654));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 655));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 656));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 657));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 658));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 659));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 660));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 661));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 662));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 663));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 664));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 665));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 666));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 667));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 668));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 669));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 670));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 671));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 672));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 673));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 674));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 675));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 676));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 677));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 678));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 679));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 680));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 681));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 682));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 683));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 684));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 685));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 686));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 687));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 688));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 689));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 690));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 691));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 692));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 693));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 694));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 695));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 696));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 697));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 698));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 699));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 700));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 701));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 702));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 703));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 704));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 705));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 706));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 707));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 708));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 709));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 710));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 711));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 712));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 713));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 714));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 715));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 716));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 717));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 718));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 719));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 720));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 721));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 722));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 723));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 724));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 725));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 726));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 727));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 728));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 729));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 730));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 731));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 732));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 733));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 734));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 735));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 736));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 737));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 738));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 739));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 740));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 741));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 742));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 743));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 744));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 745));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 746));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 747));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 748));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 749));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 750));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 751));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 752));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 753));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 754));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 755));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 756));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 757));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 758));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 759));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 760));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 761));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 762));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 763));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 764));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 765));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 766));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 767));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 768));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 769));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 770));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 771));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 772));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 773));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 774));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 775));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 776));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 777));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 778));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 779));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 780));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 781));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 782));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 783));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 784));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 785));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 786));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 787));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 788));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 789));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 790));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 791));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 792));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 793));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 794));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 795));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 796));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 797));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 798));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 799));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 800));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 801));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 802));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 803));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 804));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 805));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 806));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 807));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 808));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 809));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 810));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 811));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 812));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 813));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 814));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 815));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 816));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 817));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 818));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 819));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 820));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 821));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 822));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 823));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 824));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 825));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 826));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 827));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 828));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 829));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 830));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 831));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 832));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 833));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 834));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 835));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 836));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 837));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 838));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 839));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 840));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 841));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 842));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 843));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 844));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 845));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 846));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 847));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 848));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 849));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 850));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 851));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 852));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 853));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 854));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 855));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 856));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 857));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 858));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 859));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 860));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 861));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 862));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 863));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 864));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 865));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 866));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 867));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 868));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 869));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 870));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 871));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 872));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 873));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 874));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 875));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 876));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 877));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 878));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 879));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 880));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 881));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 882));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 883));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 884));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 885));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 886));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 887));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 888));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 889));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 890));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 891));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 892));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 893));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 894));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 895));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 896));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 897));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 898));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 899));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 900));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 901));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 902));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 903));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 904));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 905));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 906));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 907));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 908));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 909));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 910));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 911));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 912));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 913));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 914));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 915));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 916));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 917));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 918));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 919));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 920));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 921));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 922));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 923));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 924));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 925));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 926));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 927));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 928));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 929));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 930));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 931));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 932));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 933));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 934));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 935));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 936));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 937));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 938));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 939));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 940));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 941));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 942));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 943));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 944));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 945));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 946));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 947));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 948));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 949));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 950));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 951));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 952));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 953));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 954));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 955));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 956));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 957));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 958));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 959));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 960));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 961));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 962));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 963));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 964));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 965));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 966));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 967));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 968));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 969));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 970));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 971));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 972));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 973));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 974));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 975));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 976));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 977));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 978));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 979));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 980));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 981));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 982));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 983));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 984));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 985));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 986));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 987));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 988));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 989));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 990));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 991));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 992));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 993));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 994));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 995));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 996));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 997));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 998));
+  pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 999));
 
   for (final pointer in pointers) {
     Test("SimpleAddition", pointer).run();
   }
-}
\ No newline at end of file
+}
diff --git a/tests/ffi/function_callbacks_unsupported_test.dart b/tests/ffi/function_callbacks_unsupported_test.dart
new file mode 100644
index 0000000..5ac1b5d
--- /dev/null
+++ b/tests/ffi/function_callbacks_unsupported_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing that FFI callbacks report an appropriate
+// runtime error for unsupported snapshot formats.
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+bool checkError(UnsupportedError err) {
+  return "$err".contains("callbacks are not yet supported in blobs");
+}
+
+void main() {
+  Expect.throws<UnsupportedError>(
+      () => Pointer.fromFunction<Void Function()>(main), checkError);
+}
diff --git a/tests/ffi/function_gc_test.dart b/tests/ffi/function_gc_test.dart
index b212b32..ed56e34 100644
--- a/tests/ffi/function_gc_test.dart
+++ b/tests/ffi/function_gc_test.dart
@@ -6,6 +6,8 @@
 // VMOptions=--deterministic --optimization-counter-threshold=-1 --enable-testing-pragmas
 // VMOptions=--deterministic --optimization-counter-threshold=500 --enable-testing-pragmas --no-dual-map-code --write-protect-code
 // VMOptions=--deterministic --optimization-counter-threshold=-1 --enable-testing-pragmas --no-dual-map-code --write-protect-code
+// VMOptions=--enable-testing-pragmas --no-dual-map-code --write-protect-code
+// VMOptions=--enable-testing-pragmas --no-dual-map-code --write-protect-code --stacktrace-every=100
 //
 // Dart test program for stress-testing boxing and GC in return paths from FFI
 // trampolines.
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index 68529bd..b4e6d7c 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -7,8 +7,10 @@
 // VMOptions=
 // VMOptions=--deterministic --optimization-counter-threshold=10
 // VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
 // VMOptions=--write-protect-code --no-dual-map-code
 // VMOptions=--write-protect-code --no-dual-map-code --use-slow-path
+// VMOptions=--write-protect-code --no-dual-map-code --stacktrace-every=100
 // SharedObjects=ffi_test_functions
 
 library FfiTest;
diff --git a/tests/ffi/stacktrace_regress_37910_test.dart b/tests/ffi/stacktrace_regress_37910_test.dart
new file mode 100644
index 0000000..0a76648
--- /dev/null
+++ b/tests/ffi/stacktrace_regress_37910_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--stacktrace_every=100
+
+import 'dart:ffi' as ffi;
+
+typedef fooFfi1Type = ffi.Int32 Function();
+int fooFfi1() {
+  int a = 0;
+  for (int i = 0; i < 1000; ++i) {
+    a += i;
+  }
+  return a;
+}
+
+int Function() foo1 = ffi.Pointer.fromFunction<fooFfi1Type>(fooFfi1, 0)
+    .cast<ffi.NativeFunction<fooFfi1Type>>()
+    .asFunction();
+
+main() {
+  foo1();
+}
diff --git a/tests/ffi/static_checks_test.dart b/tests/ffi/static_checks_test.dart
index 0a24b6d..22d5256 100644
--- a/tests/ffi/static_checks_test.dart
+++ b/tests/ffi/static_checks_test.dart
@@ -36,6 +36,7 @@
   testFromFunctionTypeMismatch();
   testFromFunctionClosure();
   testFromFunctionTearOff();
+  testFromFunctionAbstract();
   testLookupFunctionGeneric();
   testLookupFunctionGeneric2();
   testLookupFunctionWrongNativeFunctionSignature();
@@ -248,6 +249,10 @@
   p = ffi.fromFunction(fld); //# 75: compile-time error
 }
 
+void testFromFunctionAbstract() {
+  ffi.Pointer.fromFunction<Function>(testFromFunctionAbstract);  //# 76: compile-time error
+}
+
 void testLookupFunctionGeneric() {
   Function generic<T extends Function>() {
     ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
diff --git a/tests/kernel/kernel.status b/tests/kernel/kernel.status
index 53968e2..00f926c 100644
--- a/tests/kernel/kernel.status
+++ b/tests/kernel/kernel.status
@@ -8,9 +8,3 @@
 
 [ !$fasta ]
 unsorted/loop_test: Skip # This test uses optional new/const.
-
-[ $builder_tag == obfuscated && $runtime == dart_precompiled ]
-unsorted/symbol_literal_test: RuntimeError # Issue 34911
-
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
diff --git a/tests/language_2/compile_time_constant_static5_test.dart b/tests/language_2/compile_time_constant_static5_test.dart
index 48eb09b..c1666e8 100644
--- a/tests/language_2/compile_time_constant_static5_test.dart
+++ b/tests/language_2/compile_time_constant_static5_test.dart
@@ -40,7 +40,7 @@
 
 // Will be instantiated with U=A and V=B.
 class Test3<U extends A, V extends B> {
-  final U x = const A(); //# 11: ok
+  final U x = const A(); //# 11: compile-time error
   final U x = const B(); //# 12: compile-time error
   final V x = const A(); //# 13: compile-time error
   final V x = const C(); //# 14: compile-time error
@@ -50,7 +50,7 @@
 
 // Will be instantiated with U=A and V=B.
 class Test4<U extends A, V extends A> {
-  final U x = const A(); //# 16: ok
+  final U x = const A(); //# 16: compile-time error
   final U x = const B(); //# 17: compile-time error
   final V x = const A(); //# 18: compile-time error
   final V x = const C(); //# 19: compile-time error
@@ -60,9 +60,9 @@
 
 // Will be instantiated with U=dynamic and V=dynamic.
 class Test5<U extends A, V extends B> {
-  final U x = const A(); //# 21: ok
+  final U x = const A(); //# 21: compile-time error
   final U x = const B(); //# 22: compile-time error
-  final V x = const A(); //# 23: ok
+  final V x = const A(); //# 23: compile-time error
   final V x = const C(); //# 24: compile-time error
   final V x = const C.d(); //# 25: compile-time error
   const Test5();
diff --git a/tests/language_2/config_import_corelib_general.dart b/tests/language_2/config_import_corelib_general.dart
index 04d3b5c..295f09a 100644
--- a/tests/language_2/config_import_corelib_general.dart
+++ b/tests/language_2/config_import_corelib_general.dart
@@ -4,7 +4,11 @@
 
 class Classy {
   String get name => "classy general";
+  String httpSpecific() => throw UnimplementedError();
+  String ioSpecific() => throw UnimplementedError();
 }
 
 bool general() => true;
+bool httpSpecific() => false;
+bool ioSpecific() => false;
 final String name = "general";
diff --git a/tests/language_2/config_import_corelib_http.dart b/tests/language_2/config_import_corelib_http.dart
index 292e091..857e391 100644
--- a/tests/language_2/config_import_corelib_http.dart
+++ b/tests/language_2/config_import_corelib_http.dart
@@ -7,8 +7,10 @@
 class Classy {
   String get name => "classy http";
   String httpSpecific() => "classy http";
+  String ioSpecific() => throw UnimplementedError();
 }
 
 bool general() => true;
 bool httpSpecific() => true;
+bool ioSpecific() => false;
 final String name = "http";
diff --git a/tests/language_2/config_import_corelib_io.dart b/tests/language_2/config_import_corelib_io.dart
index d5b594a..5e1543d 100644
--- a/tests/language_2/config_import_corelib_io.dart
+++ b/tests/language_2/config_import_corelib_io.dart
@@ -6,9 +6,11 @@
 
 class Classy {
   String get name => "classy io";
+  String httpSpecific() => throw UnimplementedError();
   String ioSpecific() => "classy io";
 }
 
 bool general() => true;
+bool httpSpecific() => false;
 bool ioSpecific() => true;
 final String name = "io";
diff --git a/tests/language_2/config_import_corelib_test.dart b/tests/language_2/config_import_corelib_test.dart
index 1428bd5..9267d50 100644
--- a/tests/language_2/config_import_corelib_test.dart
+++ b/tests/language_2/config_import_corelib_test.dart
@@ -26,23 +26,15 @@
     Expect.isTrue(lib.ioSpecific());
     Expect.equals("classy io", cy.ioSpecific());
 
-    Expect.throws(() {
-      lib.httpSpecific();
-    });
-    Expect.throws(() {
-      cy.httpSpecific();
-    });
+    Expect.isFalse(lib.httpSpecific());
+    Expect.throws(cy.httpSpecific);
   } else if (http) {
     Expect.isTrue(lib.general());
     Expect.equals("http", lib.name);
     Expect.equals("classy http", cy.name);
 
-    Expect.throws(() {
-      lib.ioSpecific();
-    });
-    Expect.throws(() {
-      cy.ioSpecific();
-    });
+    Expect.isFalse(lib.ioSpecific());
+    Expect.throws(cy.ioSpecific);
 
     Expect.isTrue(lib.httpSpecific());
     Expect.equals("classy http", cy.httpSpecific());
@@ -51,18 +43,10 @@
     Expect.equals("general", lib.name);
     Expect.equals("classy general", cy.name);
 
-    Expect.throws(() {
-      lib.ioSpecific();
-    });
-    Expect.throws(() {
-      cy.ioSpecific();
-    });
+    Expect.isFalse(lib.ioSpecific());
+    Expect.throws(cy.ioSpecific);
 
-    Expect.throws(() {
-      lib.httpSpecific();
-    });
-    Expect.throws(() {
-      cy.httpSpecific();
-    });
+    Expect.isFalse(lib.httpSpecific());
+    Expect.throws(cy.httpSpecific);
   }
 }
diff --git a/tests/language_2/deferred_load_library_wrong_args_test.dart b/tests/language_2/deferred_load_library_wrong_args_test.dart
index 9055eae..1cd2ded 100644
--- a/tests/language_2/deferred_load_library_wrong_args_test.dart
+++ b/tests/language_2/deferred_load_library_wrong_args_test.dart
@@ -2,7 +2,11 @@
 
 void main() {
   // Loadlibrary should be called without arguments.
-  lib.loadLibrary(
-      10 //# 01: runtime error
-      );
+  lib.loadLibrary(10);
+//^
+// [analyzer] unspecified
+// [cfe] 'loadLibrary' takes no arguments.
+  //             ^
+  // [analyzer] unspecified
+  // [cfe] Too many positional arguments: 0 allowed, but 1 found.
 }
diff --git a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
new file mode 100644
index 0000000..402ff2d
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+// Tests interactions between getters and setters where there is a conflict.
+
+// Conflicting class declarations.
+
+class C0 {
+  int get m1 => 0;
+  void set m2(int x) {}
+}
+
+extension E0 on C0 {
+  void set m1(int x) {}
+  int get m2 => 0;
+}
+
+void test0() {
+  C0 c0 = C0();
+  c0.m1;
+  c0.m1 = 0;
+  // ^^^^^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+  E0(c0).m1 = 0;
+  E0(c0).m1;
+  //     ^^
+  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+  // [cfe] unspecified
+
+  c0.m1 += 0;
+  // ^^^^^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  c0.m2 = 0;
+  c0.m2;
+  // ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+  c0.m2 += 0;
+  // ^^^^^^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+  E0(c0).m2;
+}
+
+// Conflicting extensions.
+
+class C1<T> {
+}
+
+extension E1A<T> on C1<T> {
+  int get m1 => 0;
+  void set m2(int x) {}
+}
+
+extension E1B on C1<Object> {
+  void set m1(int x) {}
+  int get m2 => 0;
+}
+
+void test1() {
+  C1<int> c1a = C1<Null>(); // E1A is more specific.
+  c1a.m1;
+
+  c1a.m1 = 0;
+  //  ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+  // [cfe] unspecified
+
+  c1a.m2;
+  //  ^^
+  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+  // [cfe] unspecified
+
+  c1a.m2 = 0;
+
+  C1<Object> c1b = C1<Null>();  // Neither extension is more specific.
+
+  c1b.m1;
+  //  ^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] unspecified
+
+  c1b.m1 = 0;
+  //  ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] unspecified
+
+  c1b.m2;
+  //  ^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] unspecified
+
+  c1b.m2 = 0;
+  //  ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] unspecified
+}
+
+// Getter on the extension itself.
+class C2 {
+  int get m1 => 0;
+  void set m2(int x) {}
+  int get mc => 0;
+}
+
+extension E2 on C2 {
+  void set m1(int x) {}
+  int get m2 => 0;
+  String get me => "";
+
+  void test2() {
+    // Using `this.member` means using the `on` type.
+
+    this.m1;
+    this.m1 = 0;
+    //   ^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+    // [cfe] unspecified
+
+    this.m2 = 0;
+    this.m2;
+    //   ^^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+    // [cfe] unspecified
+
+    // Check that `this.mc` refers to `C2.mc`.
+    this.mc.toRadixString(16);
+    // Check that `this.me` refers to `E2.me`.
+    this.me.substring(0);
+
+    // An unqualified identifier is matched against the extension (by basename).
+
+    m1 = 0;
+    1 + m1;
+    //  ^^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+    // [cfe] unspecified
+
+    1 + m2;
+    if (true) m2 = 0; // for the indent!
+    //        ^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+    // [cfe] unspecified
+
+    // Check that `mc` refers to `C2.me`.
+    mc.toRadixString(16);
+    // Check that `me` refers to `E2.me`.
+    me.substring(0);
+  }
+}
+
+main() {
+  test0();
+  test1();
+  C2().test2();
+}
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
new file mode 100644
index 0000000..855cf6d
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
@@ -0,0 +1,529 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+///////////////////////////////////////////////////////////////////////
+// The following tests check that setters or getters in an extension
+// correctly shadow members with the same basename in the surrounding
+// scope.
+///////////////////////////////////////////////////////////////////////
+
+int get topLevelGetter => -1;
+void set topLevelSetter(int _) {}
+int topLevelField = -3;
+int topLevelMethod(int x) => -4;
+
+// Check that an instance getter in an extension shadows top level
+// members with the same basename.
+extension E1 on A1 {
+  int get topLevelSetter => 1;
+  int get topLevelField => 2;
+  int get topLevelMethod => 3;
+  void test() {
+    // The instance getter shadows the global setter
+    topLevelSetter = topLevelSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The instance getter shadows the global field setter
+    topLevelField = topLevelField + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelField++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelField = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The instance getter shadows the global method
+    topLevelMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+class A1 {}
+
+// Check that an instance setter in an extension shadows top level
+// members with the same basename.
+extension E2 on A2 {
+  void set topLevelGetter(int _) {}
+  void set topLevelField(int _) {}
+  void set topLevelMethod(int _) {}
+  void test() {
+    // The instance setter shadows the global getter
+    topLevelGetter = topLevelGetter + 1;
+//                   ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelGetter = 3;
+
+    // The instance setter shadows the global field getter
+    topLevelField = topLevelField + 1;
+//                  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelField++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelField;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The instance setter shadows the global method
+    topLevelMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+class A2 {}
+
+// Check that a static getter in an extension shadows top level
+// members with the same basename.
+extension E3 on A3 {
+  static int get topLevelSetter => 1;
+  static int get topLevelField => 2;
+  static int get topLevelMethod => 3;
+  void test() {
+    // The static getter shadows the global setter
+    topLevelSetter = topLevelSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The static getter shadows the global field setter
+    topLevelField = topLevelField + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelField++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    topLevelField = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The static getter shadows the global method
+    topLevelMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+class A3 {}
+
+// Check that a static setter in an extension shadows top level
+// members with the same basename.
+extension E4 on A4 {
+  static void set topLevelGetter(int _) {}
+  static void set topLevelField(int _) {}
+  static void set topLevelMethod(int _) {}
+  void test() {
+    // The static setter shadows the global getter
+    topLevelGetter = topLevelGetter + 1;
+//                   ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static setter shadows the global field getter
+    topLevelField = topLevelField + 1;
+//                  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelField++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    topLevelField;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static setter shadows the global method
+    topLevelMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+class A4 {}
+
+// Define extensions on A6.
+extension E5 on A6 {
+  void set extensionSetter(int _) {};
+  int extensionMethod(int x) => -3;
+}
+
+// Check that an instance getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E6 on A6 {
+  int get extensionSetter => 1;
+  int get extensionMethod => 3;
+  void test() {
+    // The instance getter shadows the other extension's setter
+    extensionSetter = extensionSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The instance getter shadows the other extensions method
+    extensionMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+class A6 {}
+
+// Check that an instance getter in a class shadows extension
+// members with the same basename from extension E5.
+class A7 extends A6 {
+  int get extensionSetter => 1;
+  int get extensionMethod => 3;
+  void test() {
+    // The instance getter shadows the other extension's setter
+    extensionSetter = extensionSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The instance getter shadows the other extensions method
+    extensionMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+// Define extensions on A8.
+extension E7 on A8 {
+  int get extensionGetter => -1;
+  int extensionMethod(int x) => -3;
+}
+
+// Check that an instance setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E8 on A8 {
+  void set extensionGetter(int _) {}
+  void set extensionMethod(int _) {}
+  void test() {
+    // The instance setter shadows the other extension's getter
+    extensionGetter = extensionGetter + 1;
+//                    ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The instance setter shadows the other extension's method.
+    extensionMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+class A8 {}
+
+// Check that an instance setter in a class shadows extension
+// members with the same basename from extension E7.
+class A9 extends A8 {
+  void set extensionGetter(int _) {}
+  void set extensionMethod(int _) {}
+  void test() {
+    // The instance setter shadows the other extension's getter
+    extensionGetter = extensionGetter + 1;
+//                    ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The instance setter shadows the other extension's method.
+    extensionMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+// Define extensions on A10.
+extension E9 on A10 {
+  void set extensionSetter(int _) {}
+  void set extensionFieldSetter(int _) {}
+  int extensionMethod(int x) => -3;
+}
+
+// Check that a static getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E10 on A10 {
+  static int get extensionSetter => 1;
+  static final int extensionFieldSetter = 2;
+  static int get extensionMethod => 3;
+  void test() {
+    // The static getter shadows the other extension's setter
+    extensionSetter = extensionSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The static field shadows the other extension's setter
+    extensionFieldSetter = extensionFieldSetter + 1;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionFieldSetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionFieldSetter = 0;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static getter shadows the other extensions method
+    extensionMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+class A10 {}
+
+// Check that a static getter in a class shadows extension
+// members with the same basename from extension E9.
+class A11 extends A10 {
+  static int get extensionSetter => 1;
+  static final int extensionFieldSetter = 2;
+  static int get extensionMethod => 3;
+  void test() {
+    // The static getter shadows the other extension's setter
+    extensionSetter = extensionSetter + 1;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter++;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+    extensionSetter = 0;
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+    // The static field shadows the other extension's setter
+    extensionFieldSetter = extensionFieldSetter + 1;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionFieldSetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionFieldSetter = 0;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static getter shadows the other extensions method
+    extensionMethod(4);
+//  ^^
+// [cfe] unspecified
+//  ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+  }
+}
+
+// Define extensions on A12.
+extension E11 on A12 {
+  int get extensionGetter => -1;
+  int extensionMethod(int x) => -3;
+}
+
+// Check that a static setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E12 on A12 {
+  static void set extensionGetter(int _) {}
+  static void set extensionMethod(int _) {}
+  void test() {
+    // The static setter shadows the other extension's getter
+    extensionGetter = extensionGetter + 1;
+//                    ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static setter shadows the other extension's method.
+    extensionMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+class A12 {}
+
+// Check that a static setter in a class shadows extension
+// members with the same basename from extension E11.
+class A13 extends A12 {
+  static void set extensionGetter(int _) {}
+  static void set extensionMethod(int _) {}
+  void test() {
+    // The static setter shadows the other extension's getter
+    extensionGetter = extensionGetter + 1;
+//                    ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter++;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+    extensionGetter;
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+    // The static setter shadows the other extension's method.
+    extensionMethod(4);
+//  ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+  }
+}
+
+void main() {
+  A1().test();
+  A2().test();
+  A3().test();
+  A4().test();
+  A6().test();
+  A7().test();
+  A8().test();
+  A9().test();
+  A10().test();
+  A11().test();
+  A12().test();
+  A13().test();
+}
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart
new file mode 100644
index 0000000..519451a
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart
@@ -0,0 +1,276 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+import "package:expect/expect.dart";
+
+///////////////////////////////////////////////////////////////////////
+// The following tests check that setters or getters in an extension
+// correctly shadow members with the same basename in the surrounding
+// scope.
+///////////////////////////////////////////////////////////////////////
+
+String get topLevelGetter => "-1";
+void set topLevelSetter(String _) {}
+String topLevelField = "-3";
+String topLevelMethod(String x) => "-4";
+
+// Location that extension setters write to.
+int _storeTo = null;
+// Check that the most recent setter call set the value
+// of _storeTo.
+void checkSetter(int x) {
+  int written = _storeTo;
+  _storeTo = null;
+  Expect.equals(written, x);
+}
+
+// Check that an instance getter in an extension shadows top level
+// members with the same basename.
+extension E1 on A1 {
+  int get topLevelSetter => 1;
+  int get topLevelField => 2;
+  int get topLevelMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(topLevelSetter + 1, 2);
+    Expect.equals(topLevelField + 1, 3);
+    Expect.equals(topLevelMethod + 1, 4);
+  }
+}
+
+class A1 {}
+
+// Check that an instance setter in an extension shadows top level
+// members with the same basename.
+extension E2 on A2 {
+  void set topLevelGetter(int x) {
+    _storeTo = x;
+  }
+
+  void set topLevelField(int x) {
+    _storeTo = x;
+  }
+
+  void set topLevelMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(topLevelGetter = 42);
+    checkSetter(topLevelField = 42);
+    checkSetter(topLevelMethod = 42);
+  }
+}
+
+class A2 {}
+
+// Check that a static getter in an extension shadows top level
+// members with the same basename.
+extension E3 on A3 {
+  static int get topLevelSetter => 1;
+  static int get topLevelField => 2;
+  static int get topLevelMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(topLevelSetter + 1, 2);
+    Expect.equals(topLevelField + 1, 3);
+    Expect.equals(topLevelMethod + 1, 4);
+  }
+}
+
+class A3 {}
+
+// Check that a static setter in an extension shadows top level
+// members with the same basename.
+extension E4 on A4 {
+  static void set topLevelGetter(int x) {
+    _storeTo = x;
+  }
+
+  static void set topLevelField(int x) {
+    _storeTo = x;
+  }
+
+  static void set topLevelMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(topLevelGetter = 42);
+    checkSetter(topLevelField = 42);
+    checkSetter(topLevelMethod = 42);
+  }
+}
+
+class A4 {}
+
+// Define extensions on A6.
+extension E5 on A6 {
+  void set extensionSetter(int x) {}
+  int extensionMethod(int x) => -3;
+}
+
+// Check that an instance getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E6 on A6 {
+  int get extensionSetter => 1;
+  int get extensionMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(extensionSetter + 1, 2);
+    Expect.equals(extensionMethod + 1, 4);
+  }
+}
+
+class A6 {}
+
+// Check that an instance getter in a class shadows extension
+// members with the same basename from extension E5.
+class A7 extends A6 {
+  int get extensionSetter => 1;
+  int get extensionMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(extensionSetter + 1, 2);
+    Expect.equals(extensionMethod + 1, 4);
+  }
+}
+
+// Define extensions on A8.
+extension E7 on A8 {
+  int get extensionGetter => -1;
+  int extensionMethod(int x) => -3;
+}
+
+// Check that an instance setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E8 on A8 {
+  void set extensionGetter(int x) {
+    _storeTo = x;
+  }
+
+  void set extensionMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(extensionGetter = 42);
+    checkSetter(extensionMethod = 42);
+  }
+}
+
+class A8 {}
+
+// Check that an instance setter in a class shadows extension
+// members with the same basename from extension E7.
+class A9 extends A8 {
+  void set extensionGetter(int x) {
+    _storeTo = x;
+  }
+
+  void set extensionMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(extensionGetter = 42);
+    checkSetter(extensionMethod = 42);
+  }
+}
+
+// Define extensions on A10.
+extension E9 on A10 {
+  void set extensionSetter(int x) {}
+  void set extensionFieldSetter(int x) {}
+  int extensionMethod(int x) => -3;
+}
+
+// Check that a static getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E10 on A10 {
+  static int get extensionSetter => 1;
+  static final int extensionFieldSetter = 2;
+  static int get extensionMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(extensionSetter + 1, 2);
+    Expect.equals(extensionFieldSetter + 1, 3);
+    Expect.equals(extensionMethod + 1, 4);
+  }
+}
+
+class A10 {}
+
+// Check that a static getter in a class shadows extension
+// members with the same basename from extension E9.
+class A11 extends A10 {
+  static int get extensionSetter => 1;
+  static final int extensionFieldSetter = 2;
+  static int get extensionMethod => 3;
+  void test() {
+    // Reading the local getters is valid
+    Expect.equals(extensionSetter + 1, 2);
+    Expect.equals(extensionFieldSetter + 1, 3);
+    Expect.equals(extensionMethod + 1, 4);
+  }
+}
+
+// Define extensions on A12.
+extension E11 on A12 {
+  int get extensionGetter => -1;
+  int extensionMethod(int x) => -3;
+}
+
+// Check that a static setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E12 on A12 {
+  static void set extensionGetter(int x) {
+    _storeTo = x;
+  }
+
+  static void set extensionMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(extensionGetter = 42);
+    checkSetter(extensionMethod = 42);
+  }
+}
+
+class A12 {}
+
+// Check that a static setter in a class shadows extension
+// members with the same basename from extension E11.
+class A13 extends A12 {
+  static void set extensionGetter(int x) {
+    _storeTo = x;
+  }
+
+  static void set extensionMethod(int x) {
+    _storeTo = x;
+  }
+
+  void test() {
+    checkSetter(extensionGetter = 42);
+    checkSetter(extensionMethod = 42);
+  }
+}
+
+void main() {
+  A1().test();
+  A2().test();
+  A3().test();
+  A4().test();
+  A6().test();
+  A7().test();
+  A8().test();
+  A9().test();
+  A10().test();
+  A11().test();
+  A12().test();
+  A13().test();
+}
diff --git a/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart b/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
index f7c38dc..0a70b9b 100644
--- a/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
+++ b/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
@@ -22,41 +22,58 @@
   Expect.equals("EA.v2", a.v2);
   Expect.equals("EB1.v2", b1.v2);
   Expect.equals("EB2.v2", b2.v2);
-  c // Cannot determine which of EB1 and EB2's v2 is more specific
-    .v2 //# 01: compile-time error
-  ;
+  // Cannot determine which of EB1 and EB2's v2 is more specific
+  c.v2;
+  //^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] The getter 'v2' isn't defined for the class 'C'.
 
   Expect.equals("EA.v3", a.v3);
   Expect.equals("EA.v3", b1.v3);
   Expect.equals("EA.v3", b2.v3);
   Expect.equals("EA.v3", c.v3);
 
-
   Iterable<num> i_num = <int>[];
   Iterable<int> ii = <int>[];
   List<num> ln = <int>[];
   List<int> li = <int>[];
 
-  i_num // No `i_num` extension declared.
-    .i_num //# 02: compile-time error
-  ;
+  // No `i_num` extension declared.
+  i_num.i_num;
+  //    ^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
+  // [cfe] The getter 'i_num' isn't defined for the class 'Iterable<num>'.
 
   Expect.equals("Iterable<int>.i_num", ii.i_num);
   Expect.equals("List<num>.i_num", ln.i_num);
 
-  li // Both apply, neither is more specific.
-    .i_num //# 03: compile-time error
-  ;
+  // Both apply, neither is more specific.
+  li.i_num;
+  // ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] The getter 'i_num' isn't defined for the class 'List<int>'.
 
-  c // no most specific because both are equally specific.
-    .cs //# 04: compile-time error
-  ;
+  // no most specific because both are equally specific.
+  c.cs;
+  //^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+  // [cfe] The getter 'cs' isn't defined for the class 'C'.
+
+  // Both EIT.e1 and ELO.e1 apply, but their instantiated on
+  // types are incomparable, and hence this is an error.
+  ln.e1();
+  // ^
+  // [analyzer] unspecified
+  // [cfe] The method 'e1' isn't defined for the class 'List<num>'.
 }
 
 // Diamond class hierarchy.
 class A {}
+
 class B1 implements A {}
+
 class B2 implements A {}
+
 class C implements B1, B2 {}
 
 extension EA on A {
@@ -97,3 +114,11 @@
 extension C2 on C {
   String get cs => "C2.cs";
 }
+
+extension EIT<T> on Iterable<T> {
+  String e1() => "Iterable<T>.e1";
+}
+
+extension ELO on List<Object> {
+  String e1() => "List<Object>.e1";
+}
diff --git a/tests/language_2/extension_methods/static_extension_resolution_test.dart b/tests/language_2/extension_methods/static_extension_resolution_test.dart
index e766025..42bddbc 100644
--- a/tests/language_2/extension_methods/static_extension_resolution_test.dart
+++ b/tests/language_2/extension_methods/static_extension_resolution_test.dart
@@ -210,16 +210,16 @@
 
   // Applicable methods.
   Expect.equals("SubTarget<T>.e1", s1.e1());
-  Expect.equals("SubTarget<Object>.e2", s1.e2());
-  Expect.equals("Target<T>.e3", s1.e3());
-  Expect.equals("Target<Object>.e4", s1.e4());
+  Expect.equals("T.e2", s1.e2());
+  Expect.equals("T.e3", s1.e3());
+  Expect.equals("T.e4", s1.e4());
   Expect.equals("T.e5", s1.e5());
   Expect.equals("Object.e6", s1.e6());
 
   Expect.equals("Target<T>.e1", t1.e1());
   Expect.equals("Target<T>.e2", t1.e2());
   Expect.equals("Target<T>.e3", t1.e3());
-  Expect.equals("Target<Object>.e4", t1.e4());
+  Expect.equals("T.e4", t1.e4());
   Expect.equals("T.e5", t1.e5());
   Expect.equals("Object.e6", t1.e6());
 
diff --git a/tests/language_2/f_bounded_quantification2_test.dart b/tests/language_2/f_bounded_quantification2_test.dart
index 23d78b6..b55977b 100644
--- a/tests/language_2/f_bounded_quantification2_test.dart
+++ b/tests/language_2/f_bounded_quantification2_test.dart
@@ -4,9 +4,9 @@
 
 // Test for F-Bounded Quantification. Regression test for issue 9291.
 
-class Entities<T extends ConceptEntity<T>> implements EntitiesApi {}
+class Entities<T extends ConceptEntity<T>> implements EntitiesApi<T> {}
 
-class ConceptEntity<T extends ConceptEntity<T>> implements EntityApi {}
+class ConceptEntity<T extends ConceptEntity<T>> implements EntityApi<T> {}
 
 abstract class EntityApi<T extends EntityApi<T>> {}
 
diff --git a/tests/language_2/f_bounded_quantification4_test.dart b/tests/language_2/f_bounded_quantification4_test.dart
index d48a31d..c3f7dec 100644
--- a/tests/language_2/f_bounded_quantification4_test.dart
+++ b/tests/language_2/f_bounded_quantification4_test.dart
@@ -8,8 +8,10 @@
 
 class A<T extends B<T>> {}
 
-class B<T> extends A {}
+class B<T extends B<T>> extends A<T> {}
+
+class Foo<T extends B<T>> extends B<Foo<T>> {}
 
 main() {
-  Expect.equals("B<B<dynamic>>", new B<B>().runtimeType.toString());
+  Expect.equals("Foo<Foo<B<dynamic>>>", new Foo<Foo>().runtimeType.toString());
 }
diff --git a/tests/language_2/generic_no_such_method_dispatcher_test.dart b/tests/language_2/generic_no_such_method_dispatcher_test.dart
index 6ade491..336e7b9 100644
--- a/tests/language_2/generic_no_such_method_dispatcher_test.dart
+++ b/tests/language_2/generic_no_such_method_dispatcher_test.dart
@@ -41,13 +41,13 @@
 }
 
 main() {
-  var a = new A();
+  dynamic a = new A();
   for (var i = 0; i < 20; ++i) Expect.equals(123, a.foo<int, A>());
   Expect.throws(() => (a.foo)());
   Expect.throws(() => (a.foo)<int, A>());
   Expect.equals("123", (a.foo).toString());
 
-  var b = new B();
+  dynamic b = new B();
   for (var i = 0; i < 20; ++i) {
     Expect.equals(2, b.bar<int, A>(1));
     Expect.equals(2, b.bar(1));
@@ -63,7 +63,7 @@
   }
 
   // Test type, named, and positional arguments.
-  var c = new C([int, A], [100], {"n1": 101, "n2": 102});
+  dynamic c = new C([int, A], [100], {"n1": 101, "n2": 102});
   for (var i = 0; i < 20; ++i) {
     Expect.equals(123, c.bar<int, A>(100, n1: 101, n2: 102));
     Expect.equals(123, c.bar<int, A>(100, n2: 102, n1: 101));
diff --git a/tests/language_2/issue31596_covariant_declaration_test.dart b/tests/language_2/issue31596_covariant_declaration_test.dart
new file mode 100644
index 0000000..20defe2
--- /dev/null
+++ b/tests/language_2/issue31596_covariant_declaration_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class I0 {}
+
+class A {}
+
+class B extends A implements I0 {}
+
+class C {
+  void f(B x) {}
+}
+
+abstract class I {
+  void f(covariant A x);
+}
+
+class D extends C implements I {}
+//    ^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+// [cfe] unspecified
+
+main() {}
diff --git a/tests/language_2/issue31596_implement_covariant_test.dart b/tests/language_2/issue31596_implement_covariant_test.dart
deleted file mode 100644
index 901308c..0000000
--- a/tests/language_2/issue31596_implement_covariant_test.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-class A {}
-
-class B extends A {}
-
-class B2 extends A {}
-
-class C {
-  void f(covariant B x) {}
-}
-
-abstract class I {
-  void f(A x);
-}
-
-// This class does not require a forwarding stub; the interface of D.f is (A) ->
-// void and the implementation has signature (covariant B) -> void.  The
-// implementation satisfies the interface thanks to the presence of the
-// "covariant" keyword.
-class D extends C implements I {}
-
-main() {
-  var d = new D();
-  I i = d;
-  A a = new A();
-  B b = new B();
-  B2 b2Null = null;
-
-  // The following two lines are statically ok because the type B2 is assignable
-  // to the type A.  There should be no runtime error because the actual value
-  // at runtime is `null`, which may be assigned to A.
-  d.f(b2Null);
-  i.f(b2Null);
-
-  void Function(Object) g = d.f; // Ok; D.f reified as (Object) -> void
-  Expect.throwsTypeError(() {
-    d.f(a);
-  });
-  Expect.throwsTypeError(() {
-    i.f(a);
-  });
-}
diff --git a/tests/language_2/issue31596_override_test.dart b/tests/language_2/issue31596_override_test.dart
index 5fd37d8..592ae44 100644
--- a/tests/language_2/issue31596_override_test.dart
+++ b/tests/language_2/issue31596_override_test.dart
@@ -14,31 +14,25 @@
   void f(B x) {}
 }
 
-abstract class I1 {
-  void f(covariant A x);
+abstract class I1<X> {
+  void f(X x);
 }
 
 // This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
-//
-// For purposes of override checking, the forwarding stub is ignored.
-class D extends C implements I1 {}
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
+class D extends C implements I1<B> {}
 
 class Test extends D {
-  // Valid override - A assignable to A and B
   void f(A x) {} //# 01: ok
   void f(covariant A x) {} //# 02: ok
 
-  // Valid override - B assignable to A and B
   void f(B x) {} //# 03: ok
   void f(covariant B x) {} //# 04: ok
 
-  // Invalid override - I0 not assignable to A
-  void f(I0 x) {} //# 05: compile-time error
-  void f(covariant I0 x) {} //# 06: compile-time error
+  void f(I0 x) {} //# 05: ok
+  void f(covariant I0 x) {} //# 06: ok
 
-  // Invalid override - B2 not assignable to B
   void f(B2 x) {} //# 07: compile-time error
   void f(covariant B2 x) {} //# 08: compile-time error
 }
diff --git a/tests/language_2/issue31596_super_test.dart b/tests/language_2/issue31596_super_test.dart
index 875e4f3..86b7807 100644
--- a/tests/language_2/issue31596_super_test.dart
+++ b/tests/language_2/issue31596_super_test.dart
@@ -16,17 +16,17 @@
   void f(B x) {}
 }
 
-abstract class I {
-  void f(covariant A x);
+abstract class I<X> {
+  void f(X x);
 }
 
 // This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
 //
 // Super calls in a derived class resolve directly to C.f, and are type checked
 // accordingly at compile time.
-class D extends C implements I {}
+class D extends C implements I<B> {}
 
 class E extends D {
   void test() {
@@ -34,24 +34,26 @@
     B2 b2 = null;
 
     // ok since I0 is assignable to B
+    // TODO: Downcast from I0 to B will be a compile-time error with NNBD.
     super.f(i0); //# 01: ok
 
     // not ok since B2 is not assignable to B
     super.f(b2); //# 02: compile-time error
 
-    var superF = super.f; // Inferred type: (B) -> void
+    var superF = super.f; // Inferred static type: void Function(B)
 
     // ok since I0 is assignable to B
+    // TODO: Downcast from I0 to B will be a compile-time error with NNBD.
     superF(i0); //# 03: ok
 
     // not ok since B2 is not assignable to B
     superF(b2); //# 04: compile-time error
 
-    // Should pass since superF's runtime type is (B) -> void
+    // Should pass since superF's runtime type is void Function(Object)
     Expect.isTrue(superF is void Function(B)); //# 05: ok
-    Expect.isTrue(superF is! void Function(I0)); //# 05: continued
-    Expect.isTrue(superF is! void Function(A)); //# 05: continued
-    Expect.isTrue(superF is! void Function(Object)); //# 05: continued
+    Expect.isTrue(superF is void Function(I0)); //# 05: continued
+    Expect.isTrue(superF is void Function(A)); //# 05: continued
+    Expect.isTrue(superF is void Function(Object)); //# 05: continued
   }
 }
 
diff --git a/tests/language_2/issue31596_tearoff_test.dart b/tests/language_2/issue31596_tearoff_test.dart
index 4feba46..035a7c7 100644
--- a/tests/language_2/issue31596_tearoff_test.dart
+++ b/tests/language_2/issue31596_tearoff_test.dart
@@ -8,41 +8,41 @@
 
 class B extends A {}
 
-class B2 extends A {}
-
 class C {
   void f(B x) {}
 }
 
-abstract class I {
-  void f(covariant A x);
+abstract class I<X> {
+  void f(X x);
 }
 
 // This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
 //
 // For purposes of static type checking, the interface of the class D is
-// considered to contain a method f with signature (A) -> void.  For purposes of
+// considered to contain a method f with signature (B) -> void.  For purposes of
 // runtime behavior, a tearoff of D.f is considered to have the reified runtime
 // type (Object) -> void.
-class D extends C implements I {}
+class D extends C implements I<B> {}
 
 main() {
   var d = new D();
-  B2 b2Null = null;
-  B2 b2 = new B2();
+  A aNull = null;
+  A a = new A();
 
-  // Since the compile-time type of D.f is (A) -> void, it is assignable to (B2)
+  // Since the compile-time type of D.f is (B) -> void, it is assignable to (A)
   // -> void.  Since the runtime type is (Object) -> void, the assignment is
   // allowed at runtime as well.
-  void Function(B2) g = d.f;
+  // TODO: Implicit downcast from void Function(B) to void Function(A) will be a
+  // compile-time error with NNBD. Consider using `d.f as dynamic`.
+  void Function(A) g = d.f;
 
   // However, the tear-off performs a runtime check of its argument, so it
   // accepts a value of `null`, but it does not accept a value whose runtime
-  // type is B2.
-  g(b2Null);
+  // type is A.
+  g(aNull);
   Expect.throwsTypeError(() {
-    g(b2);
+    g(a);
   });
 }
diff --git a/tests/language_2/issue31596_test.dart b/tests/language_2/issue31596_test.dart
index 0309256..4edb2ce 100644
--- a/tests/language_2/issue31596_test.dart
+++ b/tests/language_2/issue31596_test.dart
@@ -14,33 +14,37 @@
   void f(B x, B y) {}
 }
 
-abstract class I {
-  void f(covariant A x, B y);
+abstract class I<X> {
+  void f(X x, B y);
 }
 
 // This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
 //
 // For purposes of static type checking, the interface of the class D is
-// considered to contain a method f with signature (A, B) -> void.  For purposes
+// considered to contain a method f with signature (B, B) -> void. For purposes
 // of runtime behavior, a tearoff of D.f is considered to have the reified
 // runtime type (Object, B) -> void.
-class D extends C implements I {}
+class D extends C implements I<B> {}
 
 main() {
   var d = new D();
-  I i = d;
+  I<A> i = d;
   A a = new A();
   B b = new B();
   B2 b2 = null;
-  d.f(b2, b); // Ok since B2 assignable to A
+  d.f(b2, b); //# 01: compile-time error
   i.f(b2, b); // Ok since B2 assignable to A
+  // TODO: Downcast will be a compile-time error with NNBD. Consider using
+  // `d.f as dynamic`.
   void Function(Object, B) g = d.f; // Ok; D.f reified as (Object, B) -> void
   Expect.throwsTypeError(() {
+    // TODO: Downcast will be a compile-time error with NNBD.
     d.f(a, b);
   });
   Expect.throwsTypeError(() {
+    // TODO: Downcast will be a compile-time error with NNBD.
     i.f(a, b);
   });
 }
diff --git a/tests/language_2/language_2.status b/tests/language_2/language_2.status
index 157f47f..d03e859 100644
--- a/tests/language_2/language_2.status
+++ b/tests/language_2/language_2.status
@@ -53,13 +53,6 @@
 partial_instantiation_static_bounds_check_test/02: MissingCompileTimeError # Issue 34327
 partial_instantiation_static_bounds_check_test/03: MissingCompileTimeError # Issue 34327
 
-[ $compiler != compare_analyzer_cfe && $compiler != dart2js && $compiler != spec_parser && !$fasta ]
-compile_time_constant_static5_test/11: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/16: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/21: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/23: CompileTimeError # Issue 30546
-type_promotion_more_specific_test/04: CompileTimeError # Issue 30906.
-
 [ $compiler != compare_analyzer_cfe && $compiler != spec_parser ]
 mixin_constructor_forwarding/const_constructor_test/none: CompileTimeError # Issue 32223
 mixin_constructor_forwarding/const_constructor_with_field_test/none: CompileTimeError # Issue 32223
@@ -72,46 +65,7 @@
 [ $compiler != dartk && $compiler != dartkb && $compiler != dartkp && $mode == debug && $runtime == vm ]
 built_in_identifier_type_annotation_test/set: Crash # Not supported by legacy VM front-end.
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
 [ $hot_reload || $hot_reload_rollback ]
-cha_deopt1_test: Crash # Requires deferred libraries
-cha_deopt2_test: Crash # Requires deferred libraries
-cha_deopt3_test: Crash # Requires deferred libraries
-conditional_import_string_test: Crash # Requires deferred libraries
-conditional_import_test: Crash # Requires deferred libraries
-deferred_call_empty_before_load_test: Crash # Requires deferred libraries
-deferred_closurize_load_library_test: Crash # Requires deferred libraries
-deferred_constant_list_test: Crash # Requires deferred libraries
-deferred_constraints_constants_test: Crash # Requires deferred libraries
-deferred_constraints_type_annotation_test: Crash # Requires deferred libraries
-deferred_function_type_test: Crash # Requires deferred libraries
-deferred_global_test: Crash # Requires deferred libraries
-deferred_import_core_test: Crash # Requires deferred libraries
-deferred_inheritance_constraints_test: Crash # Requires deferred libraries
-deferred_inlined_test: Crash # Requires deferred libraries
-deferred_load_constants_test: Crash # Requires deferred libraries
-deferred_load_inval_code_test: Crash # Requires deferred libraries
-deferred_load_library_wrong_args_test: Crash # Requires deferred libraries
-deferred_mixin_test: Crash # Requires deferred libraries
-deferred_no_such_method_test: Crash # Requires deferred libraries
-deferred_not_loaded_check_test: Crash # Requires deferred libraries
-deferred_only_constant_test: Crash # Requires deferred libraries
-deferred_optimized_test: Crash # Requires deferred libraries
-deferred_redirecting_factory_test: Crash # Requires deferred libraries
-deferred_regression_22995_test: Crash # Requires deferred libraries
-deferred_regression_28678_test: Crash # Requires deferred libraries
-deferred_shadow_load_library_test: Crash # Requires deferred libraries
-deferred_shared_and_unshared_classes_test: Crash # Requires deferred libraries
-deferred_static_seperate_test: Crash # Requires deferred libraries
-deferred_super_dependency_test: Pass, Crash # Requires deferred libraries
-deferred_type_dependency_test: Crash # Requires deferred libraries
-issue_1751477_test: Crash # Requires deferred libraries
 issue_22780_test/01: Pass, Crash # Issue 29094
-regress_22443_test: Crash # Requires deferred libraries
-regress_23408_test: Crash # Requires deferred libraries
-regress_28278_test: Crash # Requires deferred libraries
 static_closure_identical_test: Pass, Fail # Closure identity
 vm/optimized_stacktrace_test: Slow
-vm/regress_27201_test: Pass, Crash # Requires deferred libraries
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index 73d9383..bb945c5 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -5,90 +5,9 @@
 # Sections in this file should contain "$compiler == dart2analyzer".
 
 [ $compiler == dart2analyzer ]
-accessor_conflict_export2_test: CompileTimeError # Issue 25626
-accessor_conflict_export_test: CompileTimeError # Issue 25626
-accessor_conflict_import2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
-accessor_conflict_import_test: CompileTimeError # Issue 25626
-cascaded_forwarding_stubs_test: CompileTimeError # Issue 34329
-config_import_corelib_test: CompileTimeError, StaticWarning, OK # failing-by-design: Will never pass, see Issue #34332
-const_cast2_test/01: CompileTimeError # failing-by-design: Not a const expression, see Issue #34334
-const_cast2_test/none: CompileTimeError # failing-by-design: Not a const expression, see Issue #34334
-covariant_subtyping_with_mixin_test: CompileTimeError # Issue 34329
-dynamic_prefix_core_test/01: MissingCompileTimeError # failing-by-design: #34339
-enum_syntax_test/05: Fail # Issue 34341
-enum_syntax_test/06: Fail # Issue 34341
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-forwarding_stub_tearoff_test: CompileTimeError # Issue 34329
-generic_local_functions_test: CompileTimeError # Issue 28515
-generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
-generic_methods_generic_function_result_test/none: CompileTimeError # Issue #30207
 generic_no_such_method_dispatcher_simple_test: Skip # failing-by-design: This test is just for kernel
-generic_no_such_method_dispatcher_test: CompileTimeError # failing-by-design: This test needs to be updated for Dart 2, see Issue #34366
-generic_tearoff_test: CompileTimeError # failing-by-design: Analysis of generic function typed parameters is not yet supported
-getter_setter_in_lib_test: Fail # Issue 23286
-getters_setters2_test/01: CompileTimeError # failing-by-design: Test needs refactoring, see Issue #34365
-getters_setters_type_test/01: CompileTimeError # failing-by-design: Test needs refactoring, see Issue #34365
-hidden_import_test/01: MissingStaticWarning # failing-by-design: invalid test, see Issue #34302
-hidden_import_test/02: MissingStaticWarning # failing-by-design: invalid test, see Issue #34302
-implements_futureor_test/01: MissingCompileTimeError # Issue #33745
-implicit_creation/implicit_const_context_constructor_generic_named_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_constructor_generic_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_prefix_constructor_generic_named_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_prefix_constructor_generic_test: CompileTimeError # Issue #34367
-index_assign_operator_infer_return_type_test: CompileTimeError # failing-by-design: outdated against the spec, see Issue #34368
-initializing_formal_final_test: MissingCompileTimeError # Issue #34369
-interface_test/00: MissingCompileTimeError # Issue #34370
-invalid_returns/async_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_05_test/none: CompileTimeError # issue #34319
-issue31596_implement_covariant_test: CompileTimeError # Issue #31596
-issue31596_override_test/01: CompileTimeError # Issue #31596
-issue31596_override_test/02: CompileTimeError # Issue #31596
-issue31596_override_test/03: CompileTimeError # Issue #31596
-issue31596_override_test/04: CompileTimeError # Issue #31596
-issue31596_override_test/none: CompileTimeError # Issue #31596
-issue31596_super_test/01: CompileTimeError # Issue #31596
-issue31596_super_test/03: CompileTimeError # Issue #31596
-issue31596_super_test/05: CompileTimeError # Issue #31596
-issue31596_super_test/none: CompileTimeError # Issue #31596
-issue31596_tearoff_test: CompileTimeError # Issue #31596
-issue31596_test: CompileTimeError # Issue #31596
-issue34498_test: MissingCompileTimeError # Issue 34500
 large_class_declaration_test: Slow
-malformed2_test: Pass, MissingCompileTimeError # Flaky: issue 31056.
-nested_generic_closure_test: CompileTimeError # Issue #28515
-no_main_test/01: Fail # failing-by-design, the analyzer has no restriction that a library include a main function.
-part_of_multiple_libs_test/01: MissingCompileTimeError # Issue 33227
-part_refers_to_core_library_test/01: MissingCompileTimeError # Issue 29709
-prefix_shadow_test/01: MissingCompileTimeError # Issue 33005
 regress_23408_test: Skip # don't care about the static warning.
-regress_29025_test: CompileTimeError # Issue 29081
-regress_29405_test: CompileTimeError # Issue 29421
-regress_29784_test/02: MissingCompileTimeError # Issue 29784
-regress_33479_test/01: Crash # Issue #33479
-setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-super_setter_test: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-type_variable_static_context_negative_test: Fail # Issue 12161
 vm/debug_break_enabled_vm_test: Skip
 vm/debug_break_vm_test/*: Skip
-vm/reflect_core_vm_test: CompileTimeError # Issue 33994
 vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
-vm/regression_32912_test/01: MissingCompileTimeError # Issue 32912
-vm/regression_32912_test/02: MissingCompileTimeError # Issue 32912
-vm/regression_32912_test/03: MissingCompileTimeError # Issue 32912
-void/return_future_future_or_void_async_error1_test/none: CompileTimeError # issue #34319
-void/return_future_or_future_or_void_sync_error2_test/none: CompileTimeError # issue #34319
-void/return_future_or_void_sync_error4_test/none: CompileTimeError # issue #34319
-void/void_type_usage_test/final_local_for_in2: MissingCompileTimeError # issue 35508
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index c60a962..2478e07 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -5,86 +5,38 @@
 
 [ $compiler == dart2js ]
 arithmetic_int64_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-async_await_test/02: RuntimeError
-async_await_test/03: RuntimeError
-async_await_test/none: RuntimeError
-async_star/async_star_await_for_test: RuntimeError
-async_star/async_star_cancel_test: RuntimeError
 async_star_cancel_while_paused_test: RuntimeError # Issue 22853
-async_star_test/02: RuntimeError
 bit_operations_test: RuntimeError, OK # non JS number semantics
-bit_operations_test: RuntimeError
 bit_operations_test/03: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 bit_operations_test/04: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 bit_operations_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-call_method_as_cast_test/06: RuntimeError
-call_method_implicit_tear_off_implements_function_test/05: RuntimeError
-call_method_implicit_tear_off_implements_function_test/06: RuntimeError
-call_method_is_check_test/06: RuntimeError
 call_method_must_not_be_field_test/03: RuntimeError # Issue 32155
 call_method_must_not_be_getter_test/03: RuntimeError # Issue 32155
 canonical_const2_test: RuntimeError, OK # non JS number semantics
 closure_type_arguments_test: Crash # Issue 34272
-compile_time_constant_static5_test/11: CompileTimeError
-compile_time_constant_static5_test/16: CompileTimeError
-compile_time_constant_static5_test/21: CompileTimeError
-compile_time_constant_static5_test/23: CompileTimeError
 config_import_corelib_test: CompileTimeError # we need a special platform.dill file for categories=all. Once we fix that, all dart:* are supported when using '--categories=all' so this will become a RuntimeError, OK.
 config_import_test: RuntimeError # Test flag is not passed to the compiler.
 const_constructor3_test/04: MissingCompileTimeError # OK - Subtype check uses JS number semantics.
-const_constructor_nonconst_param_test/01: MissingCompileTimeError
 const_dynamic_type_literal_test/03: Pass # but it shouldn't until we fix issue 17207
-const_evaluation_test/01: RuntimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
 const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
 const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
-constructor_named_arguments_test/none: RuntimeError
 covariant_subtyping_test: Crash # Unsupported operation: Unsupported type parameter type node E.
-ct_const_test: RuntimeError
-deferred_load_library_wrong_args_test/01: CompileTimeError
 deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
-deferred_redirecting_factory_test: RuntimeError
 deopt_inlined_function_lazy_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 deopt_smi_op_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in dart2js; bug #11551.
 double_int_to_string_test: RuntimeError, OK # non JS number semantics
-dynamic_prefix_core_test/none: CompileTimeError
-enum_mirror_test: RuntimeError
-example_constructor_test: RuntimeError
 expect_test: RuntimeError, OK # Issue 13080
 external_test/10: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/10: MissingRuntimeError
 external_test/13: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/13: MissingRuntimeError
 external_test/20: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/20: MissingRuntimeError
-external_test/21: CompileTimeError
-external_test/24: CompileTimeError
-flatten_test/05: MissingRuntimeError
-flatten_test/08: MissingRuntimeError
-flatten_test/09: MissingRuntimeError
-flatten_test/12: MissingRuntimeError
 full_stacktrace1_test: RuntimeError # Issue 12698
 full_stacktrace2_test: RuntimeError # Issue 12698
 full_stacktrace3_test: RuntimeError # Issue 12698
-function_propagation_test: RuntimeError
-function_subtype_inline2_test: RuntimeError
-generic_function_bounds_test: RuntimeError
-generic_function_dcall_test/01: RuntimeError
-generic_is_check_test: RuntimeError
-generic_methods_bounds_test/02: MissingRuntimeError
-generic_no_such_method_dispatcher_simple_test: CompileTimeError
-generic_no_such_method_dispatcher_test: CompileTimeError
-generic_tearoff_test: CompileTimeError
 guess_cid_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 identical_closure2_test: RuntimeError # non JS number semantics
 identical_closure2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-if_null_precedence_test/none: RuntimeError
 infinity_test: RuntimeError # non JS number semantics - Issue 4984
-instance_creation_in_function_annotation_test: RuntimeError
-instantiate_tearoff_of_call_test: CompileTimeError
-instantiate_tearoff_of_call_test: RuntimeError
 int2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 int64_literal_test/01: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 int64_literal_test/02: RuntimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
@@ -99,71 +51,19 @@
 int64_literal_test/19: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 int64_literal_test/none: RuntimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 integer_division_by_zero_test: RuntimeError # Issue 8301
-internal_library_test/02: Crash
-invocation_mirror_invoke_on2_test: RuntimeError
-invocation_mirror_invoke_on_test: RuntimeError
-issue21079_test: RuntimeError
 issue23244_test: RuntimeError # Isolates - enum canonicalization - Issue 23244
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
 left_shift_test: RuntimeError # non JS number semantics
 library_env_test/has_io_support: RuntimeError, OK # dart2js doesn't support io when compiling on --categories=Client
-library_env_test/has_mirror_support: RuntimeError
 library_env_test/has_mirror_support: Fail # mirrors not supported on web
-library_env_test/has_no_html_support: RuntimeError, OK
 library_env_test/has_no_mirror_support: Pass # fails for the wrong reason.
-local_function2_test/none: RuntimeError
-local_function3_test/none: RuntimeError
-local_function_test/none: RuntimeError
-minify_closure_variable_collision_test: CompileTimeError
 mint_arithmetic_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 mint_arithmetic_test: RuntimeError # non JS number semantics
 mint_compares_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 mint_identical_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
 mixin_method_override_test/G5: Skip # Issue 34354
 mock_writable_final_field_test: RuntimeError # Issue 30847
 modulo_test: RuntimeError # non JS number semantics
-named_parameters_default_eq_test/none: RuntimeError
 nan_identical_test: RuntimeError # Issue 11551
-no_main_test/01: CompileTimeError
-no_such_method_mock_test: RuntimeError
-null_no_such_method_test: CompileTimeError
-number_identity2_test: RuntimeError
 number_identity_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 numbers_test: RuntimeError, OK # non JS number semantics
 partial_instantiation_eager_bounds_check_test: RuntimeError # Issue #34295
@@ -171,28 +71,13 @@
 partial_tearoff_instantiation_test/06: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/07: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/08: Pass # for the wrong reason.
-private_method_tearoff_test: RuntimeError
-redirecting_factory_reflection_test: RuntimeError
-regress_23408_test: CompileTimeError
 regress_24283_test: RuntimeError, OK # non JS number semantics
-regress_28255_test: RuntimeError
-regress_29025_test: CompileTimeError
-regress_29405_test: CompileTimeError
-regress_30339_test: CompileTimeError
-setter_no_getter_test/01: CompileTimeError
 stacktrace_demangle_ctors_test: RuntimeError # Issue 12698
 stacktrace_rethrow_error_test/none: RuntimeError # Issue 12698
 stacktrace_rethrow_error_test/withtraceparameter: RuntimeError # Issue 12698
 stacktrace_rethrow_nonerror_test: RuntimeError # Issue 12698
-super_bound_closure_test/none: CompileTimeError
-super_call4_test/01: MissingCompileTimeError
-super_test: RuntimeError
-tearoff_dynamic_test: RuntimeError
 truncdiv_zero_test: RuntimeError # non JS number semantics - Issue 15246
 type_constants_test/none: RuntimeError # Issue 35052
-type_error_test: RuntimeError
-type_literal_canonicalization_test: RuntimeError
-type_promotion_more_specific_test/04: CompileTimeError
 vm/*: SkipByDesign # Tests for the VM.
 
 [ $compiler != dart2js ]
@@ -201,10 +86,6 @@
 [ $builder_tag == dart2js_production && $compiler == dart2js ]
 control_flow_collections/for_non_bool_condition_test: Crash # Issue 36442
 
-[ $compiler == dart2js && $runtime == chrome ]
-field_override_optimization_test: RuntimeError
-stacktrace_test: RuntimeError
-
 [ $compiler == dart2js && $runtime == chrome && $system == macos ]
 await_future_test: Pass, Timeout # Issue 26735
 
@@ -214,14 +95,8 @@
 [ $compiler == dart2js && $runtime == d8 ]
 conditional_import_string_test: SkipByDesign # No XHR in d8
 conditional_import_test: SkipByDesign # No XHR in d8
-implicit_creation/implicit_new_constructor_generic_test: Pass
-stacktrace_test: RuntimeError
-
-[ $compiler == dart2js && $runtime == d8 && !$checked ]
-field_override_optimization_test: RuntimeError
 
 [ $compiler == dart2js && $runtime == ff ]
-field_override_optimization_test: RuntimeError
 round_test: Pass, Fail, OK # Fixed in ff 35. Common JavaScript engine Math.round bug.
 
 [ $compiler == dart2js && $runtime == jsshell ]
@@ -229,21 +104,15 @@
 async_star_await_pauses_test: RuntimeError # Need triage
 async_star_no_cancel2_test: RuntimeError # Need triage
 async_star_no_cancel_test: RuntimeError # Need triage
-async_star_test/02: RuntimeError
 await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
-field_override_optimization_test: RuntimeError
 regress_23996_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
 
 [ $compiler == dart2js && $runtime != none && $checked ]
-assert_with_message_test: RuntimeError
 syncstar_covariant_type_test: RuntimeError # dart2js misplaces check in Iterator, not Iterable.
 syncstar_dcall_type_test: RuntimeError # dart2js misplaces check in Iterator, not Iterable.
 
 [ $compiler == dart2js && $runtime == safari ]
-async_throw_in_catch_test/none: Pass, RuntimeError
-field_override_optimization_test: RuntimeError
 round_test: Fail, OK # Common JavaScript engine Math.round bug.
-stacktrace_test: RuntimeError
 
 [ $compiler == dart2js && $system == windows ]
 canonicalization_hashing_memoize_array_test: Skip # Issue 37631
@@ -253,299 +122,62 @@
 string_literals_test: Pass, RuntimeError # Failures on dart2js-win7-chrome-4-4-be and dart2js-win7-ie11ff-4-4-be
 
 [ $compiler == dart2js && $checked ]
-assign_instance_method_test: RuntimeError
-async_await_foreign_test: RuntimeError
-async_star_cancel_while_paused_test: RuntimeError
-async_star_pause_test: RuntimeError
-async_star_regression_23116_test: RuntimeError
-async_star_test/02: RuntimeError
-await_test: RuntimeError
-bit_operations_test/03: RuntimeError
-bit_operations_test/04: RuntimeError
-bit_operations_test/none: RuntimeError
 canonical_const2_test: RuntimeError, OK # non JS number semantics
-checked_method_error_order_test: RuntimeError
-class_cycle_test/02: MissingCompileTimeError
-class_cycle_test/03: MissingCompileTimeError
-conditional_method_invocation_test/05: MissingCompileTimeError
-conditional_method_invocation_test/06: MissingCompileTimeError
-conditional_method_invocation_test/07: MissingCompileTimeError
-conditional_method_invocation_test/08: MissingCompileTimeError
-conditional_method_invocation_test/12: MissingCompileTimeError
-conditional_method_invocation_test/13: MissingCompileTimeError
-conditional_method_invocation_test/18: MissingCompileTimeError
-conditional_method_invocation_test/19: MissingCompileTimeError
-conditional_property_access_test/04: MissingCompileTimeError
-conditional_property_access_test/05: MissingCompileTimeError
-conditional_property_access_test/06: MissingCompileTimeError
-conditional_property_access_test/10: MissingCompileTimeError
-conditional_property_access_test/11: MissingCompileTimeError
-conditional_property_access_test/16: MissingCompileTimeError
-conditional_property_access_test/17: MissingCompileTimeError
-conditional_property_assignment_test/04: MissingCompileTimeError
-conditional_property_assignment_test/05: MissingCompileTimeError
-conditional_property_assignment_test/06: MissingCompileTimeError
-conditional_property_assignment_test/10: MissingCompileTimeError
-conditional_property_assignment_test/11: MissingCompileTimeError
-conditional_property_assignment_test/12: MissingCompileTimeError
-conditional_property_assignment_test/13: MissingCompileTimeError
-conditional_property_assignment_test/27: MissingCompileTimeError
-conditional_property_assignment_test/28: MissingCompileTimeError
-conditional_property_assignment_test/32: MissingCompileTimeError
-conditional_property_assignment_test/33: MissingCompileTimeError
-conditional_property_assignment_test/34: MissingCompileTimeError
-conditional_property_assignment_test/35: MissingCompileTimeError
-conditional_property_increment_decrement_test/04: MissingCompileTimeError
-conditional_property_increment_decrement_test/08: MissingCompileTimeError
-conditional_property_increment_decrement_test/12: MissingCompileTimeError
-conditional_property_increment_decrement_test/16: MissingCompileTimeError
-conditional_property_increment_decrement_test/21: MissingCompileTimeError
-conditional_property_increment_decrement_test/22: MissingCompileTimeError
-conditional_property_increment_decrement_test/27: MissingCompileTimeError
-conditional_property_increment_decrement_test/28: MissingCompileTimeError
-conditional_property_increment_decrement_test/33: MissingCompileTimeError
-conditional_property_increment_decrement_test/34: MissingCompileTimeError
-conditional_property_increment_decrement_test/39: MissingCompileTimeError
-conditional_property_increment_decrement_test/40: MissingCompileTimeError
-config_import_test: RuntimeError
-const_constructor2_test/05: MissingCompileTimeError
-const_constructor2_test/06: MissingCompileTimeError
-const_constructor2_test/13: MissingCompileTimeError
-const_constructor2_test/14: MissingCompileTimeError
-const_constructor2_test/15: MissingCompileTimeError
-const_constructor2_test/16: MissingCompileTimeError
-const_constructor2_test/17: MissingCompileTimeError
-const_constructor2_test/18: MissingCompileTimeError
-const_constructor2_test/20: MissingCompileTimeError
-const_constructor2_test/22: MissingCompileTimeError
-const_constructor2_test/24: MissingCompileTimeError
-const_error_multiply_initialized_test/02: MissingCompileTimeError
-const_error_multiply_initialized_test/04: MissingCompileTimeError
-const_evaluation_test/01: RuntimeError
-const_init2_test/02: MissingCompileTimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
 const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
 const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
-const_types_test/01: MissingCompileTimeError
-const_types_test/02: MissingCompileTimeError
-const_types_test/03: MissingCompileTimeError
-const_types_test/04: MissingCompileTimeError
-const_types_test/05: MissingCompileTimeError
-const_types_test/06: MissingCompileTimeError
-const_types_test/13: MissingCompileTimeError
-const_types_test/34: MissingCompileTimeError
-const_types_test/35: MissingCompileTimeError
-const_types_test/39: MissingCompileTimeError
-const_types_test/40: MissingCompileTimeError
-constructor_duplicate_final_test/01: MissingCompileTimeError
-constructor_duplicate_final_test/02: MissingCompileTimeError
-constructor_named_arguments_test/01: MissingCompileTimeError
-constructor_named_arguments_test/none: RuntimeError
-covariant_override/runtime_check_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
-deferred_constraints_type_annotation_test/as_operation: MissingCompileTimeError
-deferred_constraints_type_annotation_test/catch_check: MissingCompileTimeError
-deferred_constraints_type_annotation_test/is_check: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_before_load: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_generic2: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_generic3: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation1: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic1: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic2: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic3: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic4: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_null: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_top_level: MissingCompileTimeError
-deferred_load_library_wrong_args_test/01: MissingRuntimeError
 deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
-deferred_redirecting_factory_test: RuntimeError
 double_int_to_string_test: RuntimeError, OK # non JS number semantics
-dynamic_prefix_core_test/none: RuntimeError
-enum_mirror_test: RuntimeError
 expect_test: RuntimeError, OK # Issue 13080
-external_test/10: MissingRuntimeError
-external_test/13: MissingRuntimeError
-external_test/20: MissingRuntimeError
-factory_redirection_test/07: MissingCompileTimeError
-final_attempt_reinitialization_test/01: MissingCompileTimeError
-final_attempt_reinitialization_test/02: MissingCompileTimeError
 full_stacktrace1_test: RuntimeError # Issue 12698
 full_stacktrace2_test: RuntimeError # Issue 12698
 full_stacktrace3_test: RuntimeError # Issue 12698
 generalized_void_syntax_test: CompileTimeError # Issue #30176.
 generic_function_dcall_test/01: Crash # Unsupported operation: Unsupported type parameter type node T.
 generic_tearoff_test: Crash # Unsupported operation: Unsupported type parameter type node T.
-generic_typedef_test: RuntimeError
 identical_closure2_test: RuntimeError # non JS number semantics
-implicit_downcast_during_assert_initializer_test: RuntimeError
 infinity_test: RuntimeError # non JS number semantics - Issue 4984
-instance_creation_in_function_annotation_test: RuntimeError
-instanceof2_test: RuntimeError
-instanceof4_test/01: RuntimeError
-instanceof4_test/none: RuntimeError
 integer_division_by_zero_test: RuntimeError # Issue 8301
 invocation_mirror2_test: RuntimeError # mirrors not supported
-issue21079_test: RuntimeError
-issue23244_test: RuntimeError
 left_shift_test: RuntimeError # non JS number semantics
-library_env_test/has_mirror_support: RuntimeError
-list_literal1_test/01: MissingCompileTimeError
-list_literal4_test/00: MissingCompileTimeError
-list_literal4_test/01: MissingCompileTimeError
-list_literal4_test/03: MissingCompileTimeError
-list_literal4_test/04: MissingCompileTimeError
-list_literal4_test/05: MissingCompileTimeError
-list_literal_syntax_test/01: MissingCompileTimeError
-list_literal_syntax_test/02: MissingCompileTimeError
-list_literal_syntax_test/03: MissingCompileTimeError
-malformed2_test/00: MissingCompileTimeError
-map_literal1_test/01: MissingCompileTimeError
-map_literal8_test: RuntimeError
 mint_arithmetic_test: RuntimeError # non JS number semantics
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/02: MissingCompileTimeError
-mixin_illegal_super_use_test/03: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/05: MissingCompileTimeError
-mixin_illegal_super_use_test/06: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/08: MissingCompileTimeError
-mixin_illegal_super_use_test/09: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
-mixin_issue10216_2_test: RuntimeError
-mixin_mixin4_test: RuntimeError
-mixin_mixin5_test: RuntimeError
-mixin_mixin7_test: RuntimeError
-mixin_mixin_bound2_test: RuntimeError
-mixin_mixin_bound_test: RuntimeError
-mixin_mixin_test: RuntimeError
-mixin_type_parameters_super_test: RuntimeError
 mock_writable_final_field_test: RuntimeError # Issue 30847
 modulo_test: RuntimeError # non JS number semantics
 nan_identical_test: RuntimeError # Issue 11551
-no_main_test/01: CompileTimeError
-not_enough_positional_arguments_test/00: MissingCompileTimeError
-not_enough_positional_arguments_test/01: MissingCompileTimeError
-not_enough_positional_arguments_test/02: MissingCompileTimeError
-not_enough_positional_arguments_test/03: MissingCompileTimeError
-not_enough_positional_arguments_test/05: MissingCompileTimeError
-not_enough_positional_arguments_test/06: MissingCompileTimeError
-not_enough_positional_arguments_test/07: MissingCompileTimeError
-number_identity2_test: RuntimeError
 numbers_test: RuntimeError, OK # non JS number semantics
-positional_parameters_type_test/01: MissingCompileTimeError
-positional_parameters_type_test/02: MissingCompileTimeError
-private_super_constructor_test/01: MissingCompileTimeError
-redirecting_factory_long_test: RuntimeError
-redirecting_factory_reflection_test: RuntimeError
-regress_20394_test/01: MissingCompileTimeError
 regress_27617_test/1: Crash # Assertion failure: Unexpected constructor j:constructor(Foo._) in ConstructorDataImpl._getConstructorConstant
-regress_28217_test/01: MissingCompileTimeError
-regress_28217_test/none: MissingCompileTimeError
-regress_28255_test: RuntimeError
-regress_28341_test: RuntimeError
-regress_29405_test: RuntimeError
-regress_30339_test: RuntimeError # Issue 26429
 regress_31057_test: Crash # Unsupported operation: Unsupported type parameter type node B.
 stacktrace_demangle_ctors_test: RuntimeError # Issue 12698
 stacktrace_rethrow_error_test/none: RuntimeError # Issue 12698
 stacktrace_rethrow_error_test/withtraceparameter: RuntimeError # Issue 12698
 stacktrace_rethrow_nonerror_test: RuntimeError # Issue 12698
 stacktrace_test: RuntimeError # Issue 12698
-symbol_literal_test/01: MissingCompileTimeError
-tearoff_dynamic_test: RuntimeError
 truncdiv_zero_test: RuntimeError # non JS number semantics - Issue 15246
-type_check_const_function_typedef2_test: MissingCompileTimeError
-type_literal_canonicalization_test: RuntimeError
 type_parameter_test/06: Crash # Internal Error: Unexpected type variable in static context.
 type_parameter_test/09: Crash # Internal Error: Unexpected type variable in static context.
 type_variable_scope_test/03: Crash # Internal Error: Unexpected type variable in static context.
 
-[ $compiler == dart2js && $checked && $minified ]
-inline_super_field_test: Crash
-typedef_is_test: Crash
-
-[ $compiler == dart2js && !$checked ]
-bool_check_test: RuntimeError
-bool_condition_check_test: RuntimeError
-issue31596_super_test/05: RuntimeError
-
 [ $compiler == dart2js && $host_checked ]
 async_return_types_test/nestedFuture: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
 async_star_cancel_while_paused_test: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
 await_not_started_immediately_test: Crash # Assertion failure: Runtime type information not available for type_variable_local(bindCallback.R) in (local(_RootZone.bindCallback#)) for j:closure_call(_RootZone_bindCallback_closure.call).
-class_literal_static_test/01: MissingCompileTimeError
-class_literal_static_test/03: MissingCompileTimeError
-class_literal_static_test/07: MissingCompileTimeError
 closure_self_reference_test: Crash # 'file:*/pkg/compiler/lib/src/ssa/nodes.dart': Failed assertion: line 641 pos 12: 'isClosed()': is not true.
-config_import_corelib_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
 issue23244_test: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
-library_env_test/has_no_html_support: RuntimeError
-map_literal3_test/03: MissingCompileTimeError
 partial_tearoff_instantiation_test/05: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
 partial_tearoff_instantiation_test/06: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
 partial_tearoff_instantiation_test/07: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
 partial_tearoff_instantiation_test/08: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
-regress_13462_1_test: RuntimeError
-regress_18535_test: RuntimeError
-type_literal_prefix_call_test/00: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
 
 [ $compiler == dart2js && $minified ]
 async_return_types_test/nestedFuture: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
 async_star_cancel_while_paused_test: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
 await_not_started_immediately_test: Crash # Assertion failure: Runtime type information not available for type_variable_local(bindCallback.R) in (local(_RootZone.bindCallback#)) for j:closure_call(_RootZone_bindCallback_closure.call).
-call_with_no_such_method_test: RuntimeError
-class_literal_static_test/01: MissingCompileTimeError
-class_literal_static_test/03: MissingCompileTimeError
-class_literal_static_test/07: MissingCompileTimeError
-config_import_corelib_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
 cyclic_type2_test: RuntimeError # Issue 31054
 cyclic_type_test/0*: RuntimeError # Issue 31054
 f_bounded_quantification4_test: RuntimeError # Issue 31054
 f_bounded_quantification5_test: RuntimeError # Issue 31054
 generic_closure_test/01: RuntimeError # Uses runtimeType.toString()
 invocation_mirror2_test: RuntimeError # mirrors not supported
-invocation_mirror_test: RuntimeError
 issue23244_test: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
-library_env_test/has_no_html_support: RuntimeError
-many_overridden_no_such_method_test: RuntimeError
-map_literal3_test/03: MissingCompileTimeError
 mixin_generic_test: RuntimeError # Issue 12605
 mixin_mixin2_test: RuntimeError # Issue 31054
 mixin_mixin3_test: RuntimeError # Issue 31054
@@ -555,15 +187,7 @@
 mixin_mixin_bound2_test: RuntimeError # Issue 31054
 mixin_mixin_bound_test: RuntimeError # Issue 31054
 mixin_mixin_type_arguments_test: RuntimeError # Issue 31054
-no_such_method_native_test: RuntimeError
-no_such_method_test: RuntimeError
-overridden_no_such_method_test: RuntimeError
-recursive_generic_test: RuntimeError
-regress_13462_1_test: RuntimeError
-regress_18535_test: RuntimeError
 regress_21795_test: RuntimeError # Issue 12605
 runtime_type_function_test: RuntimeError # Uses runtimeType.toString()
 stack_trace_test: RuntimeError, OK # Stack trace not preserved in minified code.
 symbol_conflict_test: RuntimeError # Issue 23857
-type_literal_prefix_call_test/00: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index eb9a51e..9afe4d1 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -4,386 +4,20 @@
 
 # Sections in this file should contain "$compiler == dartdevc" or dartdevk.
 [ $compiler == dartdevc ]
-accessor_conflict_export2_test: CompileTimeError # Issue 25626
-accessor_conflict_export_test: CompileTimeError # Issue 25626
-accessor_conflict_import2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
-accessor_conflict_import_test: CompileTimeError # Issue 25626
-assertion_test: RuntimeError # Issue 30326; Expect.equals(expected: <1>, actual: <0>) fails.
-async_star/async_star_await_for_test: RuntimeError
-async_star/async_star_cancel_test: RuntimeError
-async_star/async_star_test: RuntimeError
-async_star_test/01: RuntimeError
-async_star_test/03: RuntimeError
-async_star_test/04: RuntimeError
-async_star_test/05: RuntimeError
-async_star_test/none: RuntimeError
-await_future_test: Pass, Timeout # Issue 29920
-bit_operations_test: RuntimeError # No bigints on web.
-built_in_identifier_prefix_test: CompileTimeError
-built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 28816
-built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 28816
-built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 28816
-cascaded_forwarding_stubs_generic_test: RuntimeError
-cascaded_forwarding_stubs_test: CompileTimeError
-const_cast2_test/01: CompileTimeError
-const_cast2_test/none: CompileTimeError
-const_constructor3_test/04: MissingCompileTimeError # Side-effect of working around issue 33441 for int-to-double
 const_double_in_int_op_test/dd6: Skip # Triple shift
 const_double_in_int_op_test/di6: Skip # Triple shift
 const_double_in_int_op_test/id6: Skip # Triple shift
 const_double_in_int_op_test/ii6: Skip # Triple shift
-covariant_override/tear_off_type_test: RuntimeError # Issue 28395
-covariant_subtyping_with_mixin_test: CompileTimeError # Issue 34329
-deferred_load_library_wrong_args_test/01: MissingRuntimeError, RuntimeError # Issue 29920
-double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in ddc
-dynamic_prefix_core_test/01: MissingCompileTimeError
-enum_syntax_test/05: MissingCompileTimeError
-enum_syntax_test/06: MissingCompileTimeError
-execute_finally6_test: RuntimeError # Issue 29920
-expect_test: RuntimeError # Issue 29920
-export_private_test/01: MissingCompileTimeError # Issue 29920
 extension_methods/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing extension methods.
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification3_test: RuntimeError # Issue 29920
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-field_wierd_name_test: Crash
-for_test/01: MissingCompileTimeError
-forwarding_stub_tearoff_generic_test: RuntimeError
-forwarding_stub_tearoff_test: CompileTimeError
-function_propagation_test: RuntimeError
-generic_local_functions_test: CompileTimeError
-generic_methods_generic_function_parameter_test: CompileTimeError
-generic_methods_generic_function_result_test/none: CompileTimeError # Issue #30208
 generic_no_such_method_dispatcher_simple_test: Skip # This test is just for kernel.
-generic_no_such_method_dispatcher_test: CompileTimeError
-getter_closure_execution_order_test: RuntimeError # Issue 29920
-getter_setter_in_lib_test: CompileTimeError
-getters_setters2_test/01: CompileTimeError
-getters_setters_type_test/01: CompileTimeError
-implements_futureor_test/01: MissingCompileTimeError
-implicit_creation/implicit_const_context_constructor_generic_named_test: CompileTimeError
-implicit_creation/implicit_const_context_constructor_generic_test: CompileTimeError
-implicit_creation/implicit_const_context_prefix_constructor_generic_named_test: CompileTimeError
-implicit_creation/implicit_const_context_prefix_constructor_generic_test: CompileTimeError
-implicit_downcast_during_compound_assignment_test: RuntimeError
-implicit_downcast_during_indexed_compound_assignment_test: RuntimeError
-implicit_downcast_during_indexed_if_null_assignment_test: RuntimeError
-import_private_test/01: MissingCompileTimeError # Issue 29920
-index_assign_operator_infer_return_type_test: CompileTimeError
-initializing_formal_final_test: MissingCompileTimeError
-instantiate_tearoff_after_contravariance_check_test: RuntimeError
-instantiate_tearoff_of_call_test: RuntimeError
-interface_test/00: MissingCompileTimeError
-internal_library_test/01: MissingCompileTimeError # Issue 29920
-invalid_returns/async_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_05_test/none: CompileTimeError # issue #34319
-issue31596_implement_covariant_test: CompileTimeError # Issue #31596
-issue31596_override_test/01: CompileTimeError
-issue31596_override_test/02: CompileTimeError
-issue31596_override_test/03: CompileTimeError
-issue31596_override_test/04: CompileTimeError
-issue31596_override_test/none: CompileTimeError
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
-issue31596_super_test/05: CompileTimeError
-issue31596_super_test/none: CompileTimeError
-issue31596_tearoff_test: CompileTimeError
-issue31596_test: CompileTimeError
-issue34498_test: MissingCompileTimeError # Issue 34500
-label_test: RuntimeError
-labeled_variable_declaration_test: RuntimeError
-large_class_declaration_test: Slow, Pass
-left_shift_test: RuntimeError # Ints and doubles are unified.
-mixin_declaration/mixin_declaration_factory_test/02: Crash
-mixin_method_override_test/01: MissingCompileTimeError
-mixin_super_2_test: CompileTimeError # Issue 34806
-mixin_super_use_test: CompileTimeError # Issue 34806
-nested_generic_closure_test: CompileTimeError
+large_class_declaration_test: Slow
 nnbd/*: Skip
-override_inheritance_field_test/42: CompileTimeError
-part_of_multiple_libs_test/01: MissingCompileTimeError
-part_refers_to_core_library_test/01: Crash
-prefix_shadow_test/01: MissingCompileTimeError # Issue 33005
-private_method_tearoff_test: RuntimeError
-regress_22976_test: CompileTimeError # Issue 31935, test is not legal in Dart 2.
-regress_23408_test: CompileTimeError
-regress_24283_test: RuntimeError # Intended to fail, requires 64-bit numbers.
-regress_27617_test/1: MissingCompileTimeError
-regress_29025_test: CompileTimeError # Issue 29081
-regress_29405_test: CompileTimeError # Issue 29421
-regress_29784_test/02: Crash # assert initializers not implemented
-regress_29784_test/02: MissingCompileTimeError
-regress_30339_test: CompileTimeError # As expected. Should we make this a multi test?
-regress_33479_test/01: Crash # Issue #33479
-setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-stacktrace_test: RuntimeError # Issue 29920
-super_bound_closure_test/none: CompileTimeError
-super_call4_test/01: MissingCompileTimeError
-super_operator_index5_test: RuntimeError # 33470
-super_operator_index7_test: RuntimeError # 33470
-super_operator_index8_test: RuntimeError # 33470
-super_setter_test: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-syntax_test/60: MissingCompileTimeError
-syntax_test/61: MissingCompileTimeError
-truncdiv_test: RuntimeError # Issue 29920
-try_catch_on_syntax_test/10: MissingCompileTimeError
-try_catch_on_syntax_test/11: MissingCompileTimeError
-type_inference_inconsistent_inheritance_test: MissingCompileTimeError
-void/return_future_future_or_void_async_error1_test/none: CompileTimeError # issue #34319
-void/return_future_or_future_or_void_sync_error2_test/none: CompileTimeError # issue #34319
-void/return_future_or_void_sync_error4_test/none: CompileTimeError # issue #34319
-void/void_type_usage_test/final_local_for_in2: MissingCompileTimeError
-
-[ $compiler == dartdevk ]
-async_star/async_star_cancel_test: RuntimeError
-async_star/async_star_test: RuntimeError
-built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 30450, test name contains hyphen
-built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 30450, test name contains hyphen
-built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 30450, test name contains hyphen
-call_method_as_cast_test/06: RuntimeError # Kernel allows classes to subtype `Function` so DDK elides the explicit cast.
-call_method_implicit_tear_off_implements_function_test/05: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
-call_method_implicit_tear_off_implements_function_test/06: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
-call_method_must_not_be_field_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
-call_method_must_not_be_getter_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
-compile_time_constant_c_test/02: MissingCompileTimeError
-compile_time_constant_k_test/01: MissingCompileTimeError
-compile_time_constant_k_test/02: MissingCompileTimeError
-compile_time_constant_k_test/03: MissingCompileTimeError
-compile_time_constant_o_test/01: MissingCompileTimeError
-compile_time_constant_o_test/02: MissingCompileTimeError
-compile_time_constant_static4_test/02: MissingCompileTimeError
-compile_time_constant_static4_test/03: MissingCompileTimeError
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31537
-config_import_test: RuntimeError
-const_cast1_test/02: MissingCompileTimeError
-const_constructor3_test/04: MissingCompileTimeError
-const_constructor_nonconst_param_test/01: MissingCompileTimeError
-const_dynamic_type_literal_test/02: MissingCompileTimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
-const_optional_args_test/01: MissingCompileTimeError
-const_syntax_test/05: MissingCompileTimeError
-constants_test/05: MissingCompileTimeError
-covariant_subtyping_test: RuntimeError
-deferred_load_library_wrong_args_test/01: CompileTimeError
-double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in ddk
-dynamic_prefix_core_test/none: CompileTimeError
-external_test/21: CompileTimeError
-external_test/24: CompileTimeError
-function_propagation_test: RuntimeError
-generic_function_bounds_test: RuntimeError
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Warning: Superclass has no method named 'foo'.
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
-identical_const_test/01: MissingCompileTimeError
-identical_const_test/02: MissingCompileTimeError
-identical_const_test/03: MissingCompileTimeError
-identical_const_test/04: MissingCompileTimeError
-implicit_creation/implicit_const_not_default_values_test/e.*: MissingCompileTimeError
-implicit_creation/implicit_const_not_default_values_test/e12: Pass
-implicit_creation/implicit_const_not_default_values_test/e15: Pass
-implicit_creation/implicit_const_not_default_values_test/e18: Pass
-implicit_creation/implicit_const_not_default_values_test/e21: Pass
-implicit_creation/implicit_const_not_default_values_test/e24: Pass
-implicit_creation/implicit_const_not_default_values_test/e27: Pass
-implicit_creation/implicit_const_not_default_values_test/e3: Pass
-implicit_creation/implicit_const_not_default_values_test/e30: Pass
-implicit_creation/implicit_const_not_default_values_test/e6: Pass
-implicit_creation/implicit_const_not_default_values_test/e9: Pass
-instantiate_tearoff_of_call_test: CompileTimeError
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
-issue31596_super_test/05: RuntimeError
-map_literal3_test/01: MissingCompileTimeError
-map_literal3_test/02: MissingCompileTimeError
-map_literal3_test/03: MissingCompileTimeError
-mixin_declaration/mixin_declaration_subtype_test: RuntimeError
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
-mixin_super_2_test: RuntimeError # Issue 34807
-mixin_super_use_test: RuntimeError # Issue 34808
-multiline_newline_test/04: MissingCompileTimeError
-multiline_newline_test/04r: MissingCompileTimeError
-multiline_newline_test/05: MissingCompileTimeError
-multiline_newline_test/05r: MissingCompileTimeError
-multiline_newline_test/06: MissingCompileTimeError
-multiline_newline_test/06r: MissingCompileTimeError
-no_such_method_mock_test: RuntimeError # Issue 31426 - Kernel does not introduce nSM for implemented fields.
-null_no_such_method_test: CompileTimeError # Issue 31533
-redirecting_factory_reflection_test: RuntimeError # UnimplementedError: node <InvalidExpression> `invalid-expression`
-regress_23408_test: CompileTimeError # Issue 31533
-regress_24283_test: RuntimeError # Expect.equals(expected: <-1>, actual: <4294967295>) fails.
-regress_29025_test: CompileTimeError
-regress_29405_test: CompileTimeError # Issue 31402 Error: A value of type '#lib2::Foo' can't be assigned to a variable of type '(#lib2::Foo) → void'.
-regress_30339_test: CompileTimeError
-regress_30339_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
-setter_no_getter_test/01: CompileTimeError
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-super_call4_test/01: MissingCompileTimeError
-switch_bad_case_test/01: MissingCompileTimeError
-switch_bad_case_test/02: MissingCompileTimeError
-switch_case_test/00: MissingCompileTimeError
-switch_case_test/01: MissingCompileTimeError
-switch_case_test/02: MissingCompileTimeError
-syncstar_yield_test/capturing: RuntimeError
-syncstar_yield_test/copyParameters: RuntimeError # Expect.equals(expected: <2>, actual: <3>) fails.
-try_catch_test/01: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-
-[ $compiler == dartdevk && $checked ]
-assertion_initializer_const_error2_test/*: MissingCompileTimeError
-assertion_initializer_const_error2_test/none: Pass
-implicit_creation/implicit_new_constructor_generic_test: Pass
 
 [ $compiler == dartdevk && !$checked ]
 assertion_initializer_const_error2_test/*: SkipByDesign # DDC does not support non-checked mode.
 
 [ $compiler == dartdevc || $compiler == dartdevk ]
-arithmetic_int64_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-async_covariant_type_test: RuntimeError # Check too late
-async_star/async_star_await_for_test: RuntimeError
-async_star_cancel_while_paused_test: RuntimeError # Issue 29920; Uncaught Expect.listEquals(list length, expected: <4>, actual: <3>) fails: Next element <*3>
-async_star_pause_test: RuntimeError # Uncaught Expect.listEquals(at index 2, expected: <0+>, actual: <0!>) fails
-async_star_test/02: RuntimeError
-asyncstar_covariant_type_test: RuntimeError # Check too late
 asyncstar_throw_in_catch_test: Skip # Times out. Issue 29920
-bit_operations_test: RuntimeError # No bigints on web.; Expect.equals(expected: <-25>, actual: <4294967271>) fails.
-bit_operations_test/01: MissingCompileTimeError
-bit_operations_test/02: MissingCompileTimeError
-bit_operations_test/03: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-bit_operations_test/04: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-bit_operations_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-built_in_identifier_prefix_test: CompileTimeError
-canonical_const2_test: RuntimeError # Ints and doubles are unified.; Expect.isFalse(true) fails.
-closure_call_wrong_argument_count_negative_test: Fail
-compile_time_constant_d_test: RuntimeError # Issue 30876; Expect.isTrue(false) fails.
-compile_time_constant_e_test: RuntimeError # Issue 30876; Expect.identical(expected: <A 3 499 99 100>, actual: <A 3 499 99 100>) fails.
-config_import_corelib_test: CompileTimeError
-const_evaluation_test/01: RuntimeError # dart:mirrors not supported in DDC
-const_list_test: RuntimeError # Expect.equals(expected: <false>, actual: <true>) fails.
-const_switch_test/02: RuntimeError # Issue 29920; Expect.equals(expected: <0>, actual: <0.0>) fails.
-const_switch_test/04: RuntimeError # Ints and doubles are unified.; Expect.equals(expected: <1>, actual: <1.0>) fails.
-ct_const_test: RuntimeError # Issue 2992; RangeError: Maximum call stack size exceeded
-cyclic_type2_test: RuntimeError # Issue 29920; Uncaught ReferenceError: V is not defined
-cyclic_type_test/02: RuntimeError # Issue 29920; Uncaught RangeError: Maximum call stack size exceeded
-cyclic_type_test/03: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
-cyclic_type_test/04: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
-deferred_call_empty_before_load_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deferred_load_constants_test/none: RuntimeError # Issue 27394; Expect.throws fails: Did not throw
-deferred_not_loaded_check_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deferred_redirecting_factory_test: RuntimeError # Issue 27777; Uncaught Expect.throws fails: Did not throw
-deferred_static_seperate_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deopt_inlined_function_lazy_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-deopt_smi_op_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-double_int_to_string_test: RuntimeError # Issue 29920; Expect.equals(expected: <0.0>, actual: <0>) fails.
-double_to_string_as_fixed2_test/none: RuntimeError # Issue 29920; Expect.throws(ArgumentError) fails: Did not throw
-example_constructor_test: RuntimeError # Expect.equals(expected: <0 1 2 3 4 5 6 >, actual: <0 3 4 1 2 5 6 >) fails.
-exception_test: RuntimeError # DDC doesn't implement NullThrownError?; Expect.isTrue(false) fails.
-expect_test: RuntimeError # Issue 29920; Expect.identical did not fail
-f_bounded_quantification3_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: (F1, F2) => {
-flatten_test/05: MissingRuntimeError # Issue 29920
-flatten_test/08: MissingRuntimeError # Issue 29920
-flatten_test/09: MissingRuntimeError # Issue 29920
-flatten_test/12: MissingRuntimeError # Issue 29920
-for_variable_capture_test: RuntimeError # Issue 29920; Expect.equals(expected: <1>, actual: <0>) fails.
-function_subtype_inline2_test: RuntimeError # Expect.fail('Missing type error: 'new C.c1(m2)'.')
-generic_instanceof2_test: RuntimeError # Issue 29920; ReferenceError: FooOfK$String is not defined
-generic_is_check_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-generic_tearoff_test: CompileTimeError
-guess_cid_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-identical_closure2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-identical_closure2_test: RuntimeError # Issue 29920; Expect.isFalse(true) fails.
-infinite_switch_label_test: RuntimeError # Issue 29920; NoSuchMethodError: method not found: '<Unexpected Null Value>'
-infinity_test: RuntimeError # Issue 29920; Expect.isFalse(true) fails.
-instance_creation_in_function_annotation_test: RuntimeError # Issue 29920; UnimplementedError: JsClosureMirror.function unimplemented
-int2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
 int64_literal_test/*: Skip # This is testing Dart 2.0 int64 semantics.
-integer_division_by_zero_test: RuntimeError # Issue 29920; Expect.throws: Unexpected 'Unsupported operation: Infinity'
-internal_library_test/02: Crash
-invocation_mirror_invoke_on2_test: RuntimeError # UnimplementedError: JsInstanceMirror.delegate unimplemented
-invocation_mirror_invoke_on_test: RuntimeError # UnimplementedError: JsInstanceMirror.delegate unimplemented
-invocation_mirror_test: RuntimeError # Type 'NativeJavaScriptObject' is not a subtype of type 'int' in strong mode
-issue23244_test: RuntimeError # Issue 29920; Uncaught Unsupported operation: only top-level functions can be spawned.
-least_upper_bound_expansive_test/none: RuntimeError # 30908; Uncaught RangeError: Maximum call stack size exceeded
-left_shift_test: RuntimeError # Ints and doubles are unified.; Expect.equals(expected: <1>, actual: <-4294967295>) fails.
-library_env_test/has_io_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-library_env_test/has_mirror_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-library_env_test/has_no_html_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-local_function2_test/none: RuntimeError # ReferenceError: TToNull is not defined
-local_function3_test/none: RuntimeError # Expect.equals(expected: <true>, actual: <false>) fails.
-local_function_test/none: RuntimeError # Expect.equals(expected: <true>, actual: <false>) fails.
-mint_arithmetic_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mint_arithmetic_test: RuntimeError # Issue 29920; Expect.equals(expected: <4294967297>, actual: <1>) fails.
-mint_compares_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mint_identical_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-modulo_test: RuntimeError # Ints and doubles are unified.; Expect.throws fails: Did not throw
-named_parameters_default_eq_test/none: RuntimeError # Expect.isTrue(false) fails.
-nan_identical_test: RuntimeError # Issue 29920; Unsupported operation: Uint64 accessor not supported by dart2js.
-nested_switch_label_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-null_test/mirrors: RuntimeError # Uses mirrors.; ReferenceError: GenericOfT is not defined
-number_identity2_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-number_identity_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-numbers_test: RuntimeError # Issue 29920; Expect.equals(expected: <false>, actual: <true>) fails.
-regress_16640_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: E => {
-regress_22443_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
-stack_overflow_stacktrace_test: RuntimeError # Issue 29920; RangeError: Maximum call stack size exceeded
-stack_overflow_test: RuntimeError # Issue 29920; RangeError: Maximum call stack size exceeded
-stacktrace_demangle_ctors_test: RuntimeError # Issue 31089; Expect.isTrue(false) fails.
-stacktrace_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-string_literals_test: RuntimeError # Expect.equals(expected: <\x00\x0A\x0D\x7F\xFF\u{FFFF}\u{D800}\u{DC00}\u{DBFF}\u{DFFF}>, actual: <\x00\x0A\x0D\x7F\xFF\u{FFFF}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}>) fails.
-super_test: RuntimeError # Expect.equals(expected: <0>, actual: <2>) fails.
 superinterface_variance/*: Skip # Issue dart-lang/language#113
-switch_label2_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-switch_label_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-switch_try_catch_test: RuntimeError # Issue 29920; Expect.throws: Unexpected 'UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-syncstar_covariant_type_test: RuntimeError # Check too late
-truncdiv_test: RuntimeError # Issue 29920; Expect.throws fails: Did not throw
 vm/*: SkipByDesign # VM only tests.; VM only tests.
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index ee72f59..0f1d7ea 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -5,187 +5,22 @@
 
 [ $compiler == app_jitk ]
 no_main_test/01: Crash
-type_alias_equality_test/03: RuntimeError # Issue 32783
-type_alias_equality_test/04: RuntimeError # Issue 32783
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
 vm/regress_27671_test: SkipByDesign # Relies on string comparison of exception message which may return '<optimized out>'
 web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
 
 [ $compiler == dartkp ]
-generic_no_such_method_dispatcher_test: RuntimeError # Issue 31424
 web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
 
 [ $compiler == fasta ]
 async_await_syntax_test/e5: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
 async_await_syntax_test/e6: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
-constructor5_test: CompileTimeError # Verification error
-constructor6_test: CompileTimeError # Verification error
 web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
 
 [ $fasta ]
-async_return_types_test/nestedFuture: MissingCompileTimeError # Issue 33068
-const_cast2_test/01: CompileTimeError # Issue 32517
-const_cast2_test/none: CompileTimeError # Issue 32517
-constants_2018/potential_const_dynamic_test/sh3: CompileTimeError # New test introduced in https://dart-review.googlesource.com/c/sdk/+/97510
-constants_2018/potential_const_type_test/sh3: CompileTimeError # New test introduced in https://dart-review.googlesource.com/c/sdk/+/97510
-deferred_inheritance_constraints_test/extends: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_inheritance_constraints_test/implements: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_inheritance_constraints_test/mixin: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-issue31596_super_test/02: MissingCompileTimeError # Issue 31596
-issue31596_super_test/04: MissingCompileTimeError # Issue 31596
 nnbd/*: Skip
-regress_22976_test/*: CompileTimeError # Issue 31935
-set_literals/invalid_set_literal_test/08: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/09: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/10: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/29: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/30: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/31: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/32: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/33: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/34: MissingCompileTimeError # Requires constant evaluation
-superinterface_variance/abstract_class_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
 superinterface_variance/abstract_class_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/25: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/28: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
 superinterface_variance/concrete_class_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/25: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/28: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/covariance_test: CompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/37: Crash # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/38: Crash # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/40: Crash # Issue dart-lang/language#113
@@ -196,32 +31,16 @@
 superinterface_variance/mixin_error_test/46: Crash # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/47: Crash # Issue dart-lang/language#113
 superinterface_variance/mixin_error_test/48: Crash # Issue dart-lang/language#113
-syntax_test/28: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/29: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/30: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/31: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/32: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/33: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/60: MissingCompileTimeError # Issue 30470
-syntax_test/61: MissingCompileTimeError # Issue 30470
-type_constants_test/04: MissingCompileTimeError # Issue 32557
-vm/debug_break_enabled_vm_test/01: CompileTimeError # KernelVM bug: Bad test using extended break syntax.
-vm/debug_break_enabled_vm_test/none: CompileTimeError # KernelVM bug: Bad test using extended break syntax.
-vm/regress_27201_test: CompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
 
 [ $builder_tag == obfuscated && $compiler == dartkp ]
 generic_function_dcall_test/01: SkipByDesign # Prints type names
-invocation_mirror_test: RuntimeError # Issue 34911
 many_named_arguments_test: SkipByDesign # Checks names of arguments
 mixin_generic_test: SkipByDesign # Prints type names
 mixin_mixin3_test: SkipByDesign # Prints type names
 mixin_mixin5_test: SkipByDesign # Prints type names
 mixin_mixin6_test: SkipByDesign # Prints type names
 mixin_mixin_bound2_test: SkipByDesign # Prints type names
-no_such_method_native_test: RuntimeError # Compares symbol #foobar with string "foobar" in noSuchMethod
-recursive_generic_test: RuntimeError # Compares a (dynamic) toString call to 'C<D>'
 symbol_literal_test/02: SkipByDesign # We don't obfuscate const Symbol constructor
-tearoff_dynamic_test: RuntimeError # Compares call to "foo" (noSuchMethod) with string "foo"
 type_literal_test: SkipByDesign # Uses lots of strings with type names in them
 vm/bool_check_stack_traces_test: SkipByDesign # Looks for filenames in stacktrace output
 vm/no_such_args_error_message_vm_test: SkipByDesign # Looks for function name in error message
@@ -229,56 +48,9 @@
 vm/no_such_method_error_message_vm_test: SkipByDesign # Looks for unobfuscated name in error message
 vm/regress_28325_test: SkipByDesign # Looks for filename in stack trace
 
-# The precompilation and bytecode configurations use a kernel2kernel constants evaluator
-# which is is more correct than fasta/vm in JIT mode (i.e. it catches more
-# compile-time errors).
-[ $compiler != dart2analyzer && $compiler != dart2js && $compiler != dartkb && $compiler != dartkp && $fasta ]
-compile_time_constant_o_test/01: MissingCompileTimeError # Issue 32983
-compile_time_constant_o_test/02: MissingCompileTimeError # Issue 32983
-const_dynamic_type_literal_test/02: MissingCompileTimeError # Issue 32983
-identical_const_test/01: MissingCompileTimeError # Issue 32983
-identical_const_test/02: MissingCompileTimeError # Issue 32983
-identical_const_test/03: MissingCompileTimeError # Issue 32983
-identical_const_test/04: MissingCompileTimeError # Issue 32983
-
-[ $compiler != dart2analyzer && $compiler != dart2js && $fasta ]
-switch_bad_case_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_bad_case_test/02: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/02: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-
-[ $compiler != dart2analyzer && $fasta ]
-const_map2_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-const_map3_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-
-[ $compiler != dart2js && $compiler != dartdevk && $fasta ]
-const_native_factory_test: MissingCompileTimeError # Issue 29763
-
-[ $compiler != dart2js && $fasta ]
-type_constants_test/01: MissingCompileTimeError # Issue 32557
-
 [ $compiler == dartk && $mode == debug && ($hot_reload || $hot_reload_rollback) ]
 inference_enum_list_test: Skip # Issue 35885
 
-[ $compiler == dartk && $runtime == vm && !$checked ]
-assertion_initializer_const_error2_test/cc01: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc02: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc03: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc04: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc05: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc06: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc07: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc08: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc09: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc10: MissingCompileTimeError # Not reporting failed assert() at compile time.
-
-[ $compiler == dartkb && $runtime == vm ]
-async_star_test/03: Pass, RuntimeError # Please triage
-async_star_test/04: Pass, RuntimeError # Please triage
-vm/causal_async_exception_stack2_test: RuntimeError # Please triage
-vm/causal_async_exception_stack_test: RuntimeError # Please triage
-
 [ $compiler == dartkp && $mode == debug && $runtime == dart_precompiled ]
 external_test/13: Crash
 vm/precompiled_static_initializer_test: Slow
@@ -286,73 +58,28 @@
 # ==== dartkp + dart_precompiled status lines ====
 [ $compiler == dartkp && $runtime == dart_precompiled ]
 assert_with_type_test_or_cast_test: Crash
-async_star_test/02: RuntimeError, CompileTimeError # Issue 31402 (Invocation arguments)
-call_method_must_not_be_field_test/03: RuntimeError # Issue 32265
-call_method_must_not_be_getter_test/03: RuntimeError # Issue 32265
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31402 (Field declaration)
-conditional_import_string_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-conditional_import_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-config_import_corelib_test: CompileTimeError # Issue 31533
-config_import_test: RuntimeError # KernelVM bug: Configurable imports.
 const_evaluation_test: SkipByDesign
 ct_const2_test: Skip # Incompatible flag: --compile_all
-cyclic_type_test/02: Fail, OK # Non-contractive types are not supported in the vm.
-deferred_call_empty_before_load_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_constants_test/none: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_library_wrong_args_test/01: Pass # Passes by mistake. KernelVM bug: Deferred loading kernel issue 30273.
-deferred_not_loaded_check_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_redirecting_factory_test: CompileTimeError, Fail, Crash # Issue 23408, KernelVM bug: Deferred loading kernel issue 30273.
-deferred_static_seperate_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
+deferred_redirecting_factory_test: Crash # Issue 23408, KernelVM bug: Deferred loading kernel issue 30273.
 deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
 enum_mirror_test: SkipByDesign
 export_ambiguous_main_test: Skip # Issue 29895 Fail Issue 14763
 export_double_same_main_test: Skip # Issue 29895 Crash Issue 29895
-external_test/10: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/13: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/20: MissingRuntimeError # KernelVM bug: Unbound external.
 field_increment_bailout_test: SkipByDesign
 generic_methods_recursive_bound_test/03: Crash
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Issue 31533
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
 hello_dart_test: Skip # Incompatible flag: --compile_all
 implicit_closure_test: Skip # Incompatible flag: --use_slow_path
-implicit_downcast_during_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_combiner_test: Pass # Correctly passes.
-implicit_downcast_during_compound_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_conditional_expression_test: Pass # Correctly passes.
-implicit_downcast_during_do_test: Pass # Correctly passes.
-implicit_downcast_during_for_condition_test: Pass # Correctly passes.
-implicit_downcast_during_for_initializer_expression_test: Pass # Correctly passes.
-implicit_downcast_during_for_initializer_var_test: Pass # Correctly passes.
-implicit_downcast_during_if_null_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_if_statement_test: Pass # Correctly passes.
-implicit_downcast_during_list_literal_test: Pass # Correctly passes.
-implicit_downcast_during_logical_expression_test: Pass # Correctly passes.
-implicit_downcast_during_map_literal_test: Pass # Correctly passes.
-implicit_downcast_during_not_test: Pass # Correctly passes.
-implicit_downcast_during_return_async_test: Pass # Correctly passes.
-implicit_downcast_during_return_test: Pass # Correctly passes.
-implicit_downcast_during_variable_declaration_test: Pass # Correctly passes.
-implicit_downcast_during_while_statement_test: Pass # Correctly passes.
-implicit_downcast_during_yield_star_test: Pass # Correctly passes.
-implicit_downcast_during_yield_test: Pass # Correctly passes.
 instance_creation_in_function_annotation_test: SkipByDesign
 invocation_mirror2_test: SkipByDesign
 invocation_mirror_invoke_on2_test: SkipByDesign
 invocation_mirror_invoke_on_test: SkipByDesign
 issue21079_test: SkipByDesign
-library_env_test/has_html_support: RuntimeError # KernelVM bug: Configurable imports.
-library_env_test/has_no_io_support: RuntimeError # KernelVM bug: Configurable imports.
 main_not_a_function_test: Skip
 many_overridden_no_such_method_test: SkipByDesign
 mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
 mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
 no_main_test/01: Skip
 no_such_method_test: SkipByDesign
-null_no_such_method_test: CompileTimeError # Issue 31533
 null_test/mirrors: Skip # Uses mirrors.
 null_test/none: SkipByDesign
 overridden_no_such_method_test: SkipByDesign
@@ -360,47 +87,15 @@
 regress_13462_0_test: SkipByDesign
 regress_13462_1_test: SkipByDesign
 regress_18535_test: SkipByDesign
-regress_22443_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_23408_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
 regress_28255_test: SkipByDesign
-regress_29025_test: CompileTimeError # Issue 31402 (Variable declaration)
-regress_29405_test: CompileTimeError # Issue 31402 (Invocation arguments)
-regress_30339_test: CompileTimeError # Issue 31402 (Variable declaration)
-setter_no_getter_test/01: Pass, CompileTimeError # Issue 31533 (started passing after switching to batch-mode)
-string_interpolation_and_buffer_test: RuntimeError # Issue 31402 (Return and yield statements)
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-type_alias_equality_test/03: RuntimeError # Issue 32783
-type_alias_equality_test/04: RuntimeError # Issue 32783
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-vm/bool_check_stack_traces_test/01: RuntimeError # Issue 33584
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
 vm/causal_async_exception_stack2_test: SkipByDesign
 vm/causal_async_exception_stack_test: SkipByDesign
 vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
 vm/reflect_core_vm_test: SkipByDesign
 vm/regress_27671_test: Skip # Unsupported
 vm/regress_29145_test: Skip # Issue 29145
-vm/type_cast_vm_test: RuntimeError # Expects line and column numbers
-vm/type_vm_test: RuntimeError, Pass # Expects line and column numbers
 
 [ $compiler == dartkp && $runtime == dart_precompiled && $checked ]
-assert_initializer_test/31: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/32: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/33: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/34: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/35: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/36: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/37: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/38: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/41: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/42: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/43: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/44: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/45: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/46: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/47: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/48: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/none: RuntimeError # KernelVM bug: Constant evaluation.
 assertion_initializer_const_error2_test/cc01: Crash
 assertion_initializer_const_error2_test/cc02: Crash
 assertion_initializer_const_error2_test/cc03: Crash
@@ -412,17 +107,6 @@
 assertion_initializer_const_error2_test/cc09: Crash
 assertion_initializer_const_error2_test/cc10: Crash
 assertion_initializer_const_error2_test/cc11: Crash
-generic_functions_test: Pass # Issue 25869
-generic_local_functions_test: Pass # Issue 25869
-generic_methods_function_type_test: Pass # Issue 25869
-generic_methods_generic_function_parameter_test: Pass # Issue 25869
-generic_methods_new_test: Pass # Issue 25869
-generic_methods_test: Pass # Issue 25869
-known_identifier_usage_error_test/none: RuntimeError # Issue 28814
-regress_22728_test: Fail # Dartk Issue 28498
-
-[ $compiler == dartkp && $runtime == dart_precompiled && !$checked ]
-type_error_test: RuntimeError # Issue 31402 (Variable declaration)
 
 [ $compiler == dartkp && $system == windows ]
 disassemble_test: Slow
@@ -436,115 +120,28 @@
 
 [ $mode == debug && ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
 enum_duplicate_test/02: Crash # Issue 34606
-enum_duplicate_test/none: Pass, Crash # Issue 34606
-enum_private_test/01: Pass, Crash # Issue 34606
+enum_duplicate_test/none: Crash # Issue 34606
+enum_private_test/01: Crash # Issue 34606
 enum_test: Crash # Issue 34606
 
 [ $mode == product && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
 vm/causal_async_exception_stack2_test: SkipByDesign
 vm/causal_async_exception_stack_test: SkipByDesign
 
-[ $runtime == vm && $checked && ($compiler == dartk || $compiler == dartkb) ]
-assert_initializer_test/31: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/32: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/33: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/34: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/35: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/36: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/37: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/38: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/41: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/42: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/43: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/44: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/45: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/46: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/47: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/48: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/none: RuntimeError # KernelVM bug: Constant evaluation.
-
-[ $runtime == vm && !$checked && ($compiler == dartk || $compiler == dartkb) ]
-type_error_test: RuntimeError # Issue 31402 (Variable declaration)
-
 # ===== dartk + vm status lines =====
 [ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
-arithmetic2_test: RuntimeError # Throws CastError instead of TypeError
-async_star_test/02: RuntimeError # Issue 31402 (Invocation arguments)
-call_method_must_not_be_field_test/03: RuntimeError # Issue 32265
-call_method_must_not_be_getter_test/03: RuntimeError # Issue 32265
-compile_time_constant_o_test/01: RuntimeError # KernelVM bug: Constant map duplicated key.
-compile_time_constant_o_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31402 (Field declaration)
-conditional_import_string_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-conditional_import_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-config_import_corelib_test: CompileTimeError # Issue 31533
-config_import_test: RuntimeError # KernelVM bug: Configurable imports.
-const_dynamic_type_literal_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
-const_nested_test: RuntimeError # KernelVM bug: Constant evaluation.
-ct_const2_test: Pass, Crash # Flaky
-deferred_call_empty_before_load_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_constants_test/none: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_library_wrong_args_test/01: Pass # Passes by mistake. KernelVM bug: Deferred loading kernel issue 30273.
-deferred_not_loaded_check_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_redirecting_factory_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_static_seperate_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-disassemble_test: Pass, Slow, Crash # dartbug.com/34971
-external_test/10: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/13: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/20: MissingRuntimeError # KernelVM bug: Unbound external.
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Issue 31533
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
-library_env_test/has_html_support: RuntimeError # KernelVM bug: Configurable imports.
-library_env_test/has_no_io_support: RuntimeError # KernelVM bug: Configurable imports.
+ct_const2_test: Crash # Flaky
+disassemble_test: Slow, Crash # dartbug.com/34971
 mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
 mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
 no_main_test/01: Skip
-no_such_method_mock_test: RuntimeError # Issue 31426
-null_no_such_method_test: CompileTimeError # Issue 31533
-regress_22443_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_23408_test: RuntimeError, CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_29025_test: CompileTimeError # Issue 31402 (Variable declaration)
-regress_29405_test: CompileTimeError # Issue 31402 (Invocation arguments)
-regress_30339_test: CompileTimeError # Issue 31402 (Variable declaration)
-string_interpolation_and_buffer_test: RuntimeError # Issue 31402 (Return and yield statements)
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
 vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
 vm/regress_29145_test: Skip # Issue 29145
 web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
 
-[ $checked && ($compiler == dartk || $compiler == dartkb) ]
-assertion_initializer_const_error2_test/cc01: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc02: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc03: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc04: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc05: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc06: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc07: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc08: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc09: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc10: Pass # Works in --checked mode but not in --strong mode.
-
 [ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
 symbol_conflict_test: Slow
 
-# Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
-# are to be triaged.  Isolate tests are skipped on purpose due to the usage of
-# batch mode.
-[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-least_upper_bound_expansive_test/none: RuntimeError # Please triage.
-
-[ ($compiler == app_jitk || $compiler == dartk || $compiler == dartkb || $compiler == dartkp) && ($runtime == dart_precompiled || $runtime == vm) ]
-type_alias_equality_test/04: RuntimeError # Issue 32783
-
-[ ($compiler == app_jitk || $compiler == dartk || $compiler == dartkp) && ($runtime == dart_precompiled || $runtime == vm) ]
-covariant_subtyping_with_mixin_test: RuntimeError # Issue 34321
-type_alias_equality_test/03: RuntimeError # Issue 32783
-
 [ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
 async_star_test/01: Skip # Timeout
 async_star_test/02: Skip # Timeout
@@ -554,14 +151,3 @@
 async_star_test/none: Skip # Timeout
 type_constants_test/none: Skip # Deferred libraries and hot reload.
 
-[ $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
-generic_function_bounds_test: RuntimeError # Issue 32076
-
-[ $compiler == dartkb || $compiler == dartkp ]
-set_literals/invalid_set_literal_test/29: Pass # Gen_kernel does does constant
-set_literals/invalid_set_literal_test/30: Pass # evalutation, so these tests
-set_literals/invalid_set_literal_test/31: Pass # throw the expected errors. The
-set_literals/invalid_set_literal_test/32: Pass # $fasta block marks these as
-set_literals/invalid_set_literal_test/33: Pass # MissingCompileTimeError, so we
-set_literals/invalid_set_literal_test/34: Pass # need to override them to Pass.
-vm/reflect_core_vm_test: CompileTimeError # Test uses Symbol("_...") which is a compile-time error.
diff --git a/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart b/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart
new file mode 100644
index 0000000..aac6c33
--- /dev/null
+++ b/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+void main() {}
+
+void f1(NotGeneric x) {
+  x[0] + 1; //# 01: ok
+  x[0] = 1; //# 02: ok
+  useNonNullable(x[0] = 1); //# 03: ok
+  x[0] += 1; //# 04: ok
+  useNonNullable(x[0] += 1); //# 05: ok
+}
+
+void f2(NotGeneric? x) {
+  x?.[0] + 1; //# 06: compile-time error
+  x?.[0] = 1; //# 07: ok
+  useNonNullable(x?.[0] = 1); //# 08: compile-time error
+  x?.[0] += 1; //# 09: ok
+  useNonNullable(x?.[0] += 1); //# 10: compile-time error
+}
+
+void f3<T extends num>(Generic<T>? x) {
+  x?.[0] + 1; //# 11: compile-time error
+}
+
+void f4<T extends num>(Generic<T?> x) {
+  x[0] + 1; //# 12: compile-time error
+}
+
+class NotGeneric {
+  int operator[](int index) => throw 'unreachable';
+  void operator[]=(int index, int value) => throw 'unreachable';
+}
+
+class Generic<T> {
+  T operator[](int index) => throw 'unreachable';
+  void operator[]=(int index, T value) => throw 'unreachable';
+}
+
+void useNonNullable(int a) {}
diff --git a/tests/language_2/regress_22976_test.dart b/tests/language_2/regress_22976_test.dart
index d64ef30..7b54b5d 100644
--- a/tests/language_2/regress_22976_test.dart
+++ b/tests/language_2/regress_22976_test.dart
@@ -9,10 +9,16 @@
 class B<T> implements A<T> {}
 
 class C<S, T> implements B<S>, A<T> {}
+// [error line 11, column 1, length 38]
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
+//    ^
+// [cfe] 'C' can't implement both 'A<S>' and 'A<T>'
 
 main() {
   C<int, String> c1 = new C<int, String>();
   C<String, int> c2 = new C<String, int>();
-  A<int> a0 = c1; //# 01: ok
-  A<int> a1 = c2; //# 02: ok
+  A<int> a0 = c1;
+  A<int> a1 = c2;
+  //          ^
+  // [cfe] A value of type 'C<String, int>' can't be assigned to a variable of type 'A<int>'.
 }
diff --git a/tests/language_2/regress_23408_test.dart b/tests/language_2/regress_23408_test.dart
index 4372b54..5abf41d 100644
--- a/tests/language_2/regress_23408_test.dart
+++ b/tests/language_2/regress_23408_test.dart
@@ -2,33 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// This test has been modified: it is now ok to use deferred types as long as
-// they aren't instantiated.
-
 library regress_23408_test;
 
 import 'package:expect/expect.dart';
 
 import 'regress_23408_lib.dart' deferred as lib;
 
-class A<T> extends C {
-  get t => T;
-}
-
 class C {
   var v = 55;
   C();
   factory C.c() = lib.K;
-  factory C.l() = A<lib.K>;
 }
 
 void main() {
-  var a = new C.l();
-  Expect.equals(lib.K, a.t);
-  Expect.throws(() => new C.c());
   lib.loadLibrary().then((_) {
-    var b = new C.l();
-    Expect.equals(lib.K, b.t);
     var z = new C.c();
     Expect.equals(55, z.v);
   });
diff --git a/tests/language_2/regress_23408a_test.dart b/tests/language_2/regress_23408a_test.dart
new file mode 100644
index 0000000..32d3579
--- /dev/null
+++ b/tests/language_2/regress_23408a_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library regress_23408a_test;
+
+import 'package:expect/expect.dart';
+
+import 'regress_23408_lib.dart' deferred as lib;
+
+class A<T> extends C {
+  get t => T;
+}
+
+class C {
+  C();
+  factory C.l() = A<lib.K>;
+  //                ^^^^^
+  // [analyzer] STATIC_WARNING.TYPE_ANNOTATION_DEFERRED_CLASS
+  // [cfe] unspecified
+  get t => null;
+}
+
+void main() async {
+  await lib.loadLibrary();
+  Expect.equals(lib.K, C.l().t);
+}
diff --git a/tests/language_2/regress_29025_test.dart b/tests/language_2/regress_29025_test.dart
index c68f17a..867d738 100644
--- a/tests/language_2/regress_29025_test.dart
+++ b/tests/language_2/regress_29025_test.dart
@@ -2,29 +2,27 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-typedef T F<T>(T t);
+abstract class F<T> {
+  T foo(T t);
+}
 
 class B<T extends F<T>> {}
 
 class C<T extends F<C<T>>> {}
 
-class D extends B<D> {
+class D extends B<D> implements F<D> {
   D foo(D x) => x;
-  D call(D x) => x;
-  D bar(D x) => x;
 }
 
-class E extends C<E> {
+class E extends C<E> implements F<C<E>> {
   C<E> foo(C<E> x) => x;
-  C<E> call(C<E> x) => x;
-  C<E> bar(C<E> x) => x;
 }
 
 main() {
-  F<D> fd = new D();
-  var d = fd(fd);
+  D fd = D();
+  var d = fd.foo(fd);
   print(d);
-  F<E> fe = new E();
-  var e = fe(fe);
+  E fe = E();
+  var e = fe.foo(fe);
   print(e);
 }
diff --git a/tests/language_2/regress_29405_test.dart b/tests/language_2/regress_29405_test.dart
deleted file mode 100644
index 4907716..0000000
--- a/tests/language_2/regress_29405_test.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-class Foo {
-  void call(void callback(Foo foo)) {}
-}
-
-main() {
-  Foo foo = new Foo();
-  foo(foo);
-}
diff --git a/tests/language_2/regress_30339_test.dart b/tests/language_2/regress_30339_test.dart
index 59ef53f..c3a6861 100644
--- a/tests/language_2/regress_30339_test.dart
+++ b/tests/language_2/regress_30339_test.dart
@@ -7,7 +7,7 @@
 
 isCheckedMode() {
   try {
-    var i = 1;
+    dynamic i = 1;
     String s = i;
     return false;
   } on TypeError {
@@ -15,7 +15,7 @@
   }
 }
 
-var x = 'a';
+dynamic x = 'a';
 
 Future<int> foo() async {
   return x;
diff --git a/tests/language_2/super_bound_closure_test.dart b/tests/language_2/super_bound_closure_test.dart
index 55efcf0..554b0e2 100644
--- a/tests/language_2/super_bound_closure_test.dart
+++ b/tests/language_2/super_bound_closure_test.dart
@@ -72,7 +72,8 @@
   fooIntercept27() => confuse(super.lastWhere)(0);
   fooIntercept28() => confuse(super.lastWhere)(3, orElse: 77);
 
-  bar([var optional]) => -1; //       //# 01: compile-time error
+  // Warning: overrides should not change default parameter values.
+  bar([var optional]) => -1; //       //# 01: static type warning
   bar2({namedOptional}) => -1; //   //# 01: continued
   bar3(x, [var optional]) => -1; //   //# 01: continued
   bar4(x, {namedOptional}) => -1; //# 01: continued
@@ -101,7 +102,7 @@
 main() {
   var list = [new A(), new B(), [], "foo"];
   var a = list[confuse(0)];
-  var b = list[confuse(1)];
+  dynamic b = list[confuse(1)];
   var ignored = list[confuse(2)];
   var ignored2 = list[confuse(3)];
 
diff --git a/tests/language_2/type_promotion_more_specific_test.dart b/tests/language_2/type_promotion_more_specific_test.dart
index 314d7c0..03f40a7 100644
--- a/tests/language_2/type_promotion_more_specific_test.dart
+++ b/tests/language_2/type_promotion_more_specific_test.dart
@@ -54,8 +54,8 @@
     x = b.b; //# 03: ok
   }
   if (x is A) {
-    // No promotion: x has type dynamic.
-    y = x.b; //# 04: ok
+    // Promotion A << dynamic.
+    y = x.b; //# 04: compile-time error
   }
 }
 
diff --git a/tests/language_2/vm/clamp_37868_test.dart b/tests/language_2/vm/clamp_37868_test.dart
index 181f895..a6d7f21 100755
--- a/tests/language_2/vm/clamp_37868_test.dart
+++ b/tests/language_2/vm/clamp_37868_test.dart
@@ -13,8 +13,15 @@
 @pragma("vm:never-inline")
 foo(List<int> x) => Uint8ClampedList.fromList(x);
 
+@pragma("vm:never-inline")
+bar(List<int> x) => Uint8List.fromList(x);
+
+@pragma("vm:never-inline")
+baz(List<int> x) => Int8List.fromList(x);
+
 main() {
-  var x = [
+  // Proper values.
+  final List<int> x = [
     9223372036854775807,
     -9223372036854775808,
     9223372032559808513,
@@ -25,10 +32,34 @@
     -2147483648,
     255,
     -255,
+    11,
+    -11,
+    0,
+    -1,
   ];
-  var y = foo(x);
-  for (int i = 0; i < y.length; i += 2) {
-    Expect.equals(255, y[i]);
-    Expect.equals(0, y[i + 1]);
+  Expect.listEquals(
+      [255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 11, 0, 0, 0], foo(x));
+  Expect.listEquals(
+      [255, 0, 1, 255, 0, 0, 255, 0, 255, 1, 11, 245, 0, 255], bar(x));
+  Expect.listEquals([-1, 0, 1, -1, 0, 0, -1, 0, -1, 1, 11, -11, 0, -1], baz(x));
+
+  // Hidden null.
+  final List<int> a = [1, null, 2];
+  int num_exceptions = 0;
+  try {
+    foo(a);
+  } on NoSuchMethodError catch (e) {
+    num_exceptions++;
   }
+  try {
+    bar(a);
+  } on NoSuchMethodError catch (e) {
+    num_exceptions++;
+  }
+  try {
+    baz(a);
+  } on NoSuchMethodError catch (e) {
+    num_exceptions++;
+  }
+  Expect.equals(3, num_exceptions);
 }
diff --git a/tests/language_2/vm/div_mod_test.dart b/tests/language_2/vm/div_mod_test.dart
new file mode 100755
index 0000000..92fab4f
--- /dev/null
+++ b/tests/language_2/vm/div_mod_test.dart
@@ -0,0 +1,302 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--deterministic
+
+// Unit tests on DIV and MOV operations by various constants.
+
+import "package:expect/expect.dart";
+
+import 'dart:core';
+
+int kMin = 0x8000000000000000;
+int kMax = 0x7fffffffffffffff;
+
+// The basic DIV operation.
+int divme(int x, int c) {
+  return x ~/ c;
+}
+
+// The basic MOD operation.
+int modme(int x, int c) {
+  return x % c;
+}
+
+//
+// Test several "hidden" DIV constants.
+//
+
+@pragma("vm:never-inline")
+int div0(int x) {
+  return divme(x, 0);
+}
+
+@pragma("vm:never-inline")
+int div1(int x) {
+  return divme(x, 1);
+}
+
+@pragma("vm:never-inline")
+int divm1(int x) {
+  return divme(x, -1);
+}
+
+@pragma("vm:never-inline")
+int div2(int x) {
+  return divme(x, 2);
+}
+
+@pragma("vm:never-inline")
+int divm2(int x) {
+  return divme(x, -2);
+}
+
+@pragma("vm:never-inline")
+int div37(int x) {
+  return divme(x, 37);
+}
+
+@pragma("vm:never-inline")
+int div131(int x) {
+  return divme(x, 131);
+}
+
+@pragma("vm:never-inline")
+int divm333(int x) {
+  return divme(x, -333);
+}
+
+@pragma("vm:never-inline")
+int divmin(int x) {
+  return divme(x, kMin);
+}
+
+@pragma("vm:never-inline")
+int divmax(int x) {
+  return divme(x, kMax);
+}
+
+//
+// Test several "hidden" MOD constants.
+//
+
+@pragma("vm:never-inline")
+int mod0(int x) {
+  return modme(x, 0);
+}
+
+@pragma("vm:never-inline")
+int mod1(int x) {
+  return modme(x, 1);
+}
+
+@pragma("vm:never-inline")
+int modm1(int x) {
+  return modme(x, -1);
+}
+
+@pragma("vm:never-inline")
+int mod2(int x) {
+  return modme(x, 2);
+}
+
+@pragma("vm:never-inline")
+int modm2(int x) {
+  return modme(x, -2);
+}
+
+@pragma("vm:never-inline")
+int mod37(int x) {
+  return modme(x, 37);
+}
+
+@pragma("vm:never-inline")
+int mod131(int x) {
+  return modme(x, 131);
+}
+
+@pragma("vm:never-inline")
+int modm333(int x) {
+  return modme(x, -333);
+}
+
+@pragma("vm:never-inline")
+int modmin(int x) {
+  return modme(x, kMin);
+}
+
+@pragma("vm:never-inline")
+int modmax(int x) {
+  return modme(x, kMax);
+}
+
+main() {
+  // Exceptional case DIV.
+  for (int i = -1; i <= 1; i++) {
+    bool threw = false;
+    try {
+      div0(i);
+    } on IntegerDivisionByZeroException catch (e) {
+      threw = true;
+    }
+    Expect.isTrue(threw);
+  }
+
+  // Exceptional case MOD.
+  for (int i = -1; i <= 1; i++) {
+    bool threw = false;
+    try {
+      mod0(i);
+    } on IntegerDivisionByZeroException catch (e) {
+      threw = true;
+    }
+    Expect.isTrue(threw);
+  }
+
+  // DIV by +/- 1.
+  Expect.equals(kMin, div1(kMin));
+  Expect.equals(kMin, divm1(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(i, div1(i));
+    Expect.equals(-i, divm1(i));
+  }
+  Expect.equals(kMax, div1(kMax));
+  Expect.equals(-kMax, divm1(kMax));
+
+  // MOD by +/- 1.
+  Expect.equals(0, mod1(kMin));
+  Expect.equals(0, modm1(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(0, mod1(i));
+    Expect.equals(0, modm1(i));
+  }
+  Expect.equals(0, mod1(kMax));
+  Expect.equals(0, modm1(kMax));
+
+  // DIV by +/- 2.
+  Expect.equals(-4611686018427387904, div2(kMin));
+  Expect.equals(-4611686018427387903, div2(kMin + 1));
+  Expect.equals(-4611686018427387903, div2(kMin + 2));
+  Expect.equals(4611686018427387904, divm2(kMin));
+  Expect.equals(4611686018427387903, divm2(kMin + 1));
+  Expect.equals(4611686018427387903, divm2(kMin + 2));
+  for (int i = -999; i <= 999; i++) {
+    int e = (i + ((i < 0) ? 1 : 0)) >> 1;
+    Expect.equals(e, div2(i));
+    Expect.equals(-e, divm2(i));
+  }
+  Expect.equals(4611686018427387903, div2(kMax));
+  Expect.equals(4611686018427387903, div2(kMax - 1));
+  Expect.equals(4611686018427387902, div2(kMax - 2));
+  Expect.equals(-4611686018427387903, divm2(kMax));
+  Expect.equals(-4611686018427387903, divm2(kMax - 1));
+  Expect.equals(-4611686018427387902, divm2(kMax - 2));
+
+  // MOD by +/- 2.
+  Expect.equals(0, mod2(kMin));
+  Expect.equals(1, mod2(kMin + 1));
+  Expect.equals(0, mod2(kMin + 2));
+  Expect.equals(0, modm2(kMin));
+  Expect.equals(1, modm2(kMin + 1));
+  Expect.equals(0, modm2(kMin + 2));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(i & 1, mod2(i));
+    Expect.equals(i & 1, modm2(i));
+  }
+  Expect.equals(1, mod2(kMax));
+  Expect.equals(0, mod2(kMax - 1));
+  Expect.equals(1, mod2(kMax - 2));
+  Expect.equals(1, modm2(kMax));
+  Expect.equals(0, modm2(kMax - 1));
+  Expect.equals(1, modm2(kMax - 2));
+
+  // DIV/MOD by 37.
+  Expect.equals(-249280325320399346, div37(kMin));
+  Expect.equals(31, mod37(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(i, div37(37 * i));
+    Expect.equals(i, div37(37 * i + ((i >= 0) ? 36 : -36)));
+    Expect.equals(0, mod37(37 * i));
+    Expect.equals(1, mod37(37 * i + 1));
+    Expect.equals(36, mod37(37 * i + 36));
+  }
+  for (int i = 1; i < 37; i++) {
+    Expect.equals(0, div37(i));
+    Expect.equals(i, mod37(i));
+    Expect.equals(0, div37(-i));
+    Expect.equals(37 - i, mod37(-i));
+  }
+  Expect.equals(249280325320399346, div37(kMax));
+  Expect.equals(5, mod37(kMax));
+
+  // DIV/MOD by 131.
+  Expect.equals(-70407420128662410, div131(kMin));
+  Expect.equals(33, mod131(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(i, div131(131 * i));
+    Expect.equals(i, div131(131 * i + ((i >= 0) ? 130 : -130)));
+    Expect.equals(0, mod131(131 * i));
+    Expect.equals(1, mod131(131 * i + 1));
+    Expect.equals(130, mod131(131 * i + 130));
+  }
+  for (int i = 1; i < 131; i++) {
+    Expect.equals(0, div131(i));
+    Expect.equals(i, mod131(i));
+    Expect.equals(0, div131(-i));
+    Expect.equals(131 - i, mod131(-i));
+  }
+  Expect.equals(70407420128662410, div131(kMax));
+  Expect.equals(97, mod131(kMax));
+
+  // DIV/MOD by -333.
+  Expect.equals(27697813924488816, divm333(kMin));
+  Expect.equals(253, modm333(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(i, divm333(-333 * i));
+    Expect.equals(i, divm333(-333 * i + ((i < 0) ? 130 : -130)));
+    Expect.equals(0, modm333(-333 * i));
+    Expect.equals(1, modm333(-333 * i + 1));
+    Expect.equals(130, modm333(-333 * i + 130));
+  }
+  Expect.equals(-27697813924488816, divm333(kMax));
+  Expect.equals(79, modm333(kMax));
+
+  // DIV/MOD by Min.
+  Expect.equals(1, divmin(kMin));
+  Expect.equals(0, modmin(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(0, divmin(i));
+    Expect.equals(i >= 0 ? i : 1 + kMax + i, modmin(i));
+  }
+  Expect.equals(0, divmin(kMax));
+  Expect.equals(kMax, modmin(kMax));
+
+  // DIV/MOD by Max.
+  Expect.equals(-1, divmax(kMin));
+  Expect.equals(kMax - 1, modmax(kMin));
+  for (int i = -999; i <= 999; i++) {
+    Expect.equals(0, divmax(i));
+    Expect.equals(i >= 0 ? i : kMax + i, modmax(i));
+  }
+  Expect.equals(1, divmax(kMax));
+  Expect.equals(0, modmax(kMax));
+
+  // Exceptional null value MOD.
+  bool threwDiv = false;
+  try {
+    div2(null);
+  } on NoSuchMethodError catch (e) {
+    threwDiv = true;
+  }
+  Expect.isTrue(threwDiv);
+
+  // Exceptional null value MOD.
+  bool threwMod = false;
+  try {
+    mod2(null);
+  } on NoSuchMethodError catch (e) {
+    threwMod = true;
+  }
+  Expect.isTrue(threwMod);
+}
diff --git a/tests/language_2/vm/regress_37984_test.dart b/tests/language_2/vm/regress_37984_test.dart
new file mode 100644
index 0000000..2e7cd6f
--- /dev/null
+++ b/tests/language_2/vm/regress_37984_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+main() async {
+  await for (var x in func(3)) {
+    print(x);
+  }
+}
+
+Stream<int> func(int i) async* {
+  int currentState = 0;
+  try {
+    print('outer try');
+  } finally {
+    try {
+      print('inner try');
+    } finally {
+      yield currentState + 1;
+    }
+    yield currentState + 1;
+    print('finally');
+  }
+}
diff --git a/tests/language_2/vm/regression_37821_test.dart b/tests/language_2/vm/regression_37821_test.dart
new file mode 100755
index 0000000..fd7ef2d
--- /dev/null
+++ b/tests/language_2/vm/regression_37821_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--deterministic
+
+import "package:expect/expect.dart";
+
+import 'dart:typed_data';
+
+// Found by DartFuzzing: inconsistent view of unboxing
+// https://github.com/dart-lang/sdk/issues/37821
+
+double var5 = 0.5521203015696288;
+
+class X0 {
+  double fld0_1 = 0.44794902547497595;
+  void run() {
+    for (int loc1 = 0; loc1 < 11; loc1++) {
+      var5 = fld0_1;
+    }
+    fld0_1 -= 20;
+  }
+}
+
+class X1 extends X0 {
+  void run() {
+    super.run();
+  }
+}
+
+@pragma("vm:never-inline")
+void checkMe(double value) {
+  Expect.approxEquals(0.44794902547497595, value);
+}
+
+main() {
+  Expect.approxEquals(0.5521203015696288, var5);
+  new X1().run();
+  checkMe(var5);
+}
diff --git a/tests/language_2/vm/regression_38147_test.dart b/tests/language_2/vm/regression_38147_test.dart
new file mode 100755
index 0000000..0f3450a
--- /dev/null
+++ b/tests/language_2/vm/regression_38147_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--deterministic --optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+import 'dart:typed_data';
+
+// Found by DartFuzzing: truncating shift
+// https://github.com/dart-lang/sdk/issues/38147
+
+int bar(int x, int y) {
+  return (x << y) & 0xffff;
+}
+
+@pragma("vm:never-inline")
+int foo() {
+  return bar(-61, 12);
+}
+
+main() {
+  for (int i = 0; i < 20; i++) {
+    Expect.equals(12288, foo());
+  }
+}
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index 0d9adbc..097b176 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -117,9 +117,6 @@
 [ $runtime != dart_precompiled && ($runtime != vm || $compiler != dartk && $compiler != none) ]
 isolate/vm_rehash_test: SkipByDesign
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
 [ $arch == simarm || $arch == simarmv5te || $arch == simarmv6 ]
 convert/utf85_test: Skip # Pass, Slow Issue 12644.
 
diff --git a/tests/lib_2/lib_2_analyzer.status b/tests/lib_2/lib_2_analyzer.status
index 85a2a1d..113c571 100644
--- a/tests/lib_2/lib_2_analyzer.status
+++ b/tests/lib_2/lib_2_analyzer.status
@@ -3,8 +3,4 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2analyzer ]
-html/element_types_keygen_test: CompileTimeError # Chrome 57 keygen removed
 html/js_function_getter_trust_types_test: Skip # dart2js specific flags.
-html/js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
-mirrors/deferred_type_test: CompileTimeError, OK # Deliberately refers to a deferred type in a declaration.
-mirrors/repeated_private_anon_mixin_app_test: CompileTimeError, OK # Intentional library name conflict.
diff --git a/tests/lib_2/lib_2_dart2js.status b/tests/lib_2/lib_2_dart2js.status
index b96429f..e1c07ea 100644
--- a/tests/lib_2/lib_2_dart2js.status
+++ b/tests/lib_2/lib_2_dart2js.status
@@ -3,10 +3,6 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js ]
-async/future_or_type_test: RuntimeError
-async/slow_consumer2_test: RuntimeError
-async/stream_distinct_test: RuntimeError
-collection/list_test: RuntimeError
 convert/chunked_conversion_utf88_test: Slow
 convert/utf85_test: Slow
 developer/timeline_test: Skip # Not supported
@@ -19,7 +15,6 @@
 html/custom/mirrors_2_test: Skip # mirrors not supported, delete this test.
 html/custom/mirrors_test: Skip # mirrors not supported, delete this test.
 html/custom_elements_test: Slow # Issue 26789
-html/element_classes_test: RuntimeError
 html/isolates_test: SkipByDesign
 html/mirrors_js_typed_interop_test: Skip # mirrors not supported, delete this test.
 html/worker_api_test: SkipByDesign
@@ -38,28 +33,10 @@
 convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
 html/element_types_keygen_test: RuntimeError # Issue 29055
-html/file_sample_test: Pass, RuntimeError
-html/fileapi_entry_test: Pass, RuntimeError
-html/interactive_media_test: RuntimeError
 html/media_stream_test: RuntimeError # Please triage.
 html/speechrecognition_test: RuntimeError # Please triage.
 
 [ $compiler == dart2js && $runtime == chrome && $csp ]
-html/canvas_pixel_array_type_alias_test: RuntimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_test: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_identity_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_methods_test: RuntimeError
-html/js_transferrables_test: RuntimeError
-html/js_typed_interop_lazy_test/none: RuntimeError
-html/js_typed_interop_rename_static_test: RuntimeError
 html/worker_test/functional: RuntimeError # Issue 32261
 
 [ $compiler == dart2js && $runtime == chromeOnAndroid ]
@@ -80,275 +57,35 @@
 typed_data/setRange_3_test: RuntimeError # TODO(dart2js-team): Please triage this failure.
 
 [ $compiler == dart2js && $runtime == d8 ]
-async/dart2js_uncaught_error_test: RuntimeError
-html/async_test: RuntimeError
-html/audiobuffersourcenode_test: RuntimeError
-html/audiocontext_test: RuntimeError
-html/audioelement_test: RuntimeError
-html/b_element_test: RuntimeError
-html/blob_constructor_test: RuntimeError
-html/cache_test: RuntimeError
-html/callback_list_test: RuntimeError
-html/callbacks_test: RuntimeError
-html/canvas_pixel_array_type_alias_test: RuntimeError
-html/canvas_test: RuntimeError
-html/canvasrenderingcontext2d_test: RuntimeError
-html/cdata_test: RuntimeError
-html/client_rect_test: RuntimeError
-html/cross_domain_iframe_test: RuntimeError
-html/crypto_test: RuntimeError
-html/css_rule_list_test: RuntimeError
-html/css_test: RuntimeError
-html/cssstyledeclaration_test: RuntimeError
-html/custom/attribute_changed_callback_test: RuntimeError
-html/custom/constructor_calls_created_synchronously_test: RuntimeError
-html/custom/created_callback_test: RuntimeError
-html/custom/document_register_basic_test: RuntimeError
-html/custom/document_register_template_test: RuntimeError
-html/custom/document_register_type_extensions_test: RuntimeError
-html/custom/element_upgrade_test: RuntimeError
-html/custom/entered_left_view_test: RuntimeError
-html/custom/js_custom_test: RuntimeError
-html/custom_element_method_clash_test: RuntimeError
-html/custom_element_name_clash_test: RuntimeError
-html/custom_elements_23127_test: RuntimeError
-html/custom_elements_test: RuntimeError
-html/custom_tags_test: RuntimeError
-html/dart_object_local_storage_test: RuntimeError
-html/datalistelement_test: RuntimeError
-html/document_test: RuntimeError
-html/documentfragment_test: RuntimeError
-html/dom_constructors_test: RuntimeError
-html/domparser_test: RuntimeError
-html/element_add_test: RuntimeError
-html/element_animate_test: RuntimeError
-html/element_classes_svg_test: RuntimeError
-html/element_constructor_1_test: RuntimeError
-html/element_dimensions_test: RuntimeError
-html/element_offset_test: RuntimeError
-html/element_test: RuntimeError
-html/element_types_constructors1_test: RuntimeError
-html/element_types_constructors2_test: RuntimeError
-html/element_types_constructors3_test: RuntimeError
-html/element_types_constructors4_test: RuntimeError
-html/element_types_constructors5_test: RuntimeError
-html/element_types_constructors6_test: RuntimeError
-html/element_types_content_test: RuntimeError
-html/element_types_datalist_test: RuntimeError
-html/element_types_details_test: RuntimeError
-html/element_types_embed_test: RuntimeError
-html/element_types_keygen_test: RuntimeError
-html/element_types_meter_test: RuntimeError
-html/element_types_object_test: RuntimeError
-html/element_types_output_test: RuntimeError
-html/element_types_progress_test: RuntimeError
-html/element_types_shadow_test: RuntimeError
-html/element_types_template_test: RuntimeError
-html/element_types_track_test: RuntimeError
 html/event_callback_test: Skip # Browser test
-html/event_customevent_test: RuntimeError
-html/event_test: RuntimeError
-html/events_test: RuntimeError
-html/exceptions_test: RuntimeError
-html/file_sample_test: RuntimeError
-html/fileapi_directory_reader_test: RuntimeError
-html/fileapi_directory_test: RuntimeError
-html/fileapi_entry_test: RuntimeError
-html/fileapi_file_entry_test: RuntimeError
-html/fileapi_file_test: RuntimeError
-html/fileapi_supported_test: RuntimeError
-html/fileapi_supported_throws_test: RuntimeError
-html/filereader_test: RuntimeError
-html/filteredelementlist_test: RuntimeError
-html/fontface_loaded_test: RuntimeError
-html/fontface_test: RuntimeError
-html/form_data_test: RuntimeError
-html/form_element_test: RuntimeError
-html/gamepad_test: RuntimeError
-html/geolocation_test: RuntimeError
-html/hidden_dom_1_test: RuntimeError
-html/hidden_dom_2_test: RuntimeError
-html/history_hash_change_test: RuntimeError
-html/history_history_test: RuntimeError
-html/history_test: RuntimeError
-html/html_mock_test: RuntimeError
-html/htmlcollection_test: RuntimeError
-html/htmlelement_test: RuntimeError
-html/htmloptionscollection_test: RuntimeError
-html/indexeddb_1_test: RuntimeError
-html/indexeddb_2_test: RuntimeError
-html/indexeddb_4_test: RuntimeError
-html/input_element_attributes_test: RuntimeError
-html/input_element_constructor_test: RuntimeError
-html/input_element_date_test: RuntimeError
-html/input_element_datetime_test: RuntimeError
-html/input_element_email_test: RuntimeError
-html/input_element_month_test: RuntimeError
-html/input_element_number_test: RuntimeError
-html/input_element_range_test: RuntimeError
-html/input_element_search_test: RuntimeError
-html/input_element_tel_test: RuntimeError
-html/input_element_time_test: RuntimeError
-html/input_element_url_test: RuntimeError
-html/input_element_week_test: RuntimeError
-html/instance_of_test: RuntimeError
-html/interactive_media_test: RuntimeError
-html/interactive_test: RuntimeError
-html/isolates_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_array_test: CompileTimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_test: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_dart_to_string_test: RuntimeError
-html/js_dispatch_property_test: CompileTimeError
-html/js_dispatch_property_test: RuntimeError
-html/js_extend_class_test: RuntimeError
-html/js_function_getter_test: RuntimeError
-html/js_function_getter_trust_types_test: RuntimeError
-html/js_identity_test: RuntimeError
-html/js_interop_1_test: RuntimeError
-html/js_interop_constructor_name_div_test: RuntimeError
-html/js_interop_constructor_name_error1_test: RuntimeError
-html/js_interop_constructor_name_error2_test: RuntimeError
-html/js_interop_constructor_name_method_test: RuntimeError
-html/js_javascript_function_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_methods_test: RuntimeError
-html/js_transferrables_test: RuntimeError
-html/js_typed_interop_bind_this_test: RuntimeError
-html/js_typed_interop_callable_object_test: RuntimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
-html/js_typed_interop_default_arg_test/none: RuntimeError
-html/js_typed_interop_dynamic_test: RuntimeError
-html/js_typed_interop_lazy_test/01: RuntimeError
-html/js_typed_interop_lazy_test/none: RuntimeError
-html/js_typed_interop_rename_static_test: RuntimeError
-html/js_typed_interop_test: CompileTimeError
-html/js_typed_interop_type1_test/01: RuntimeError
-html/js_typed_interop_type1_test/none: RuntimeError
-html/js_typed_interop_type3_test/01: RuntimeError
-html/js_typed_interop_type3_test/02: RuntimeError
-html/js_typed_interop_type3_test/none: RuntimeError
-html/js_typed_interop_type_test: RuntimeError
-html/js_typed_interop_window_property_test: RuntimeError
-html/js_util_test: RuntimeError
-html/keyboard_event_test: RuntimeError
-html/localstorage_test: RuntimeError
-html/location_test: RuntimeError
-html/media_stream_test: RuntimeError
-html/mediasource_test: RuntimeError
-html/message_channel_test: RuntimeError
-html/messageevent_test: RuntimeError
-html/mirrors_js_typed_interop_test: RuntimeError
-html/mouse_event_test: RuntimeError
-html/mutationobserver_test: RuntimeError
-html/native_gc_test: RuntimeError
-html/navigator_test: RuntimeError
-html/node_test: RuntimeError
-html/node_validator_important_if_you_suppress_make_the_bug_critical_test: RuntimeError
-html/notification_permission_test: RuntimeError
-html/notification_test: RuntimeError
-html/performance_api_test: RuntimeError
-html/postmessage_structured_test: RuntimeError
-html/private_extension_member_test: RuntimeError
-html/query_test: RuntimeError
-html/queryall_test: RuntimeError
-html/range_test: RuntimeError
-html/request_animation_frame_test: RuntimeError
-html/rtc_test: RuntimeError
-html/selectelement_test: RuntimeError
-html/serialized_script_value_test: RuntimeError
-html/shadow_dom_test: RuntimeError
-html/shadowroot_test: RuntimeError
-html/speechrecognition_test: RuntimeError
-html/storage_promise_test: RuntimeError
-html/storage_test: RuntimeError
-html/streams_test: RuntimeError
-html/svg_test: RuntimeError
-html/svgelement_test: RuntimeError
-html/table_test: RuntimeError
-html/text_event_test: RuntimeError
-html/touchevent_test: RuntimeError
-html/track_element_constructor_test: RuntimeError
-html/transferables_test: RuntimeError
-html/transition_event_test: RuntimeError
-html/trusted_html_tree_sanitizer_test: RuntimeError
-html/typed_arrays_1_test: RuntimeError
-html/typed_arrays_2_test: RuntimeError
-html/typed_arrays_3_test: RuntimeError
-html/typed_arrays_4_test: RuntimeError
-html/typed_arrays_5_test: RuntimeError
-html/typed_arrays_arraybuffer_test: RuntimeError
-html/typed_arrays_dataview_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
-html/typed_arrays_simd_test: RuntimeError
-html/typing_test: RuntimeError
-html/unknownelement_test: RuntimeError
-html/uri_test: RuntimeError
-html/url_test: RuntimeError
-html/webgl_1_test: RuntimeError
-html/webgl_extensions_test: RuntimeError
-html/websocket_test: RuntimeError
-html/websql_test: RuntimeError
-html/wheelevent_test: RuntimeError
-html/window_eq_test: RuntimeError
-html/window_mangling_test: RuntimeError
-html/window_nosuchmethod_test: RuntimeError
-html/window_test: RuntimeError
-html/worker_api_test: RuntimeError
-html/worker_test: RuntimeError
-html/xhr_cross_origin_test: RuntimeError
-html/xhr_test: RuntimeError
-html/xsltprocessor_test: RuntimeError
-js/null_test: RuntimeError
-js/prototype_access_test: RuntimeError
-
-[ $compiler == dart2js && $runtime == d8 && $minified ]
-collection/list_test: RuntimeError
 
 [ $compiler == dart2js && $runtime != d8 ]
 html/html_mock_test: RuntimeError # Issue 31038
-html/input_element_attributes_test: RuntimeError
-html/js_extend_class_test: RuntimeError
 
 [ $compiler == dart2js && $runtime == ff ]
 async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
-convert/utf85_test: Pass, Slow, Timeout
+convert/utf85_test: Slow
 html/callback_list_test: SkipByDesign # FileSystem not supported in FireFox.
 html/custom/attribute_changed_callback_test: Skip # Times out
-html/custom/constructor_calls_created_synchronously_test: Pass, Timeout
 html/custom/created_callback_test: Skip # Times out
 html/custom/document_register_basic_test: Skip # Times out, or unittest times out
 html/dart_object_local_storage_test: Skip # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
 html/element_animate_test/timing_dict: RuntimeError # Issue 26730
 html/element_types_content_test: Pass, RuntimeError # Issues 28983, 29922
-html/element_types_keygen_test: Fail
 html/element_types_keygen_test: RuntimeError # Issue 29922
 html/element_types_shadow_test: Pass, RuntimeError # Issues 28983, 29922
 html/file_sample_test: Skip # FileSystem not supported on FireFox.
 html/fileapi_supported_test: Skip # FileSystem not supported on FireFox.
 html/fileapi_supported_throws_test: Skip # FileSystem not supported on FireFox.
 html/fontface_test: Fail # Fontface not supported on ff
-html/gamepad_test: RuntimeError
 html/history_test/history: Skip # Issue 22050
-html/input_element_datetime_test: Fail
-html/input_element_month_test: Fail
-html/input_element_week_test: Fail
 html/interactive_media_test: RuntimeError # Not supported in FF
-html/media_stream_test: Fail
 html/messageevent_test: Pass, RuntimeError # Issue 28983
 html/request_animation_frame_test: Skip # Async test hangs.
 html/serialized_script_value_test: Pass, RuntimeError # Issue 28983
-html/shadow_dom_test: Fail
 html/speechrecognition_test: RuntimeError # Please triage.
 html/text_event_test: Fail # Issue 17893
 html/webgl_1_test: Pass, Fail # Issue 8219
@@ -366,8 +103,6 @@
 html/element_types_shadow_test: RuntimeError # Issue 29922
 html/element_types_template_test: RuntimeError # Issue 29922
 html/element_types_track_test: RuntimeError # Issue 29922
-math/math2_test: RuntimeError
-math/math_test: RuntimeError
 
 [ $compiler == dart2js && $runtime == jsshell ]
 async/catch_errors12_test: Fail # Timer interface not supported: Issue 7728.
@@ -388,7 +123,6 @@
 async/periodic_timer4_test: Fail # Timer interface not supported: Issue 7728.
 async/run_zoned7_test: RuntimeError # Timer interface not supported: Issue 7728.
 async/run_zoned8_test: Fail # Timer interface not supported: Issue 7728.
-async/schedule_microtask3_test: RuntimeError
 async/schedule_microtask_test: Fail # Preamble file does not correctly implement scheduleImmediate.
 async/slow_consumer2_test: RuntimeError # Timer interface not supported; Issue 7728.
 async/slow_consumer3_test: RuntimeError # Timer interface not supported; Issue 7728.
@@ -418,22 +152,9 @@
 async/zone_create_timer2_test: RuntimeError # Timer interface not supported: Issue 7728.
 async/zone_empty_description2_test: RuntimeError # Timer interface not supported: Issue 7728.
 
-[ $compiler == dart2js && $runtime != jsshell ]
-async/timer_not_available_test: RuntimeError
-
 [ $compiler == dart2js && $runtime == safari ]
-html/audiobuffersourcenode_test: RuntimeError
-html/audiobuffersourcenode_test: Pass, RuntimeError
 html/callback_list_test: SkipByDesign # FileSystem not supported in Safari.
-html/canvasrenderingcontext2d_test/arc: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/drawImage_canvas_element: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/drawImage_image_element: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/fillText: Pass, RuntimeError
 html/css_test/functional/functional: RuntimeError # Issue 32576
-html/custom/attribute_changed_callback_test: RuntimeError, Timeout
-html/custom/constructor_calls_created_synchronously_test: Pass, Timeout
-html/custom/created_callback_test: Pass, Timeout
-html/custom/document_register_basic_test: Pass, Timeout
 html/element_types_content_test: RuntimeError # Issue 29922
 html/element_types_datalist_test: RuntimeError # Issue 29922
 html/element_types_shadow_test: RuntimeError # Issue 29922
@@ -442,22 +163,12 @@
 html/interactive_media_test: SkipSlow
 html/notification_test: Pass, RuntimeError # Safari doesn't let us access the fields of the Notification to verify them.
 html/storage_promise_test: RuntimeError # Not supported on Safari
-html/xhr_test: RuntimeError
 
 [ $compiler == dart2js && $system == linux ]
 html/interactive_geolocation_test: Skip # Requires allowing geo location.
 
-[ $compiler == dart2js && $system == windows ]
-html/xhr_test: RuntimeError
-
 [ $compiler == dart2js && $browser ]
-html/custom/created_callback_test: RuntimeError
-html/element_classes_svg_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_typed_interop_lazy_test/01: RuntimeError
 html/notification_permission_test: Timeout, Pass # Issue 32002
-html/private_extension_member_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
 js/null_test: RuntimeError # Issue 30652
 
 [ $compiler == dart2js && $browser && $csp ]
@@ -465,13 +176,9 @@
 html/custom/js_custom_test: Fail # Issue 14643
 
 [ $compiler == dart2js && $checked ]
-async/stream_listen_zone_test: RuntimeError
 convert/utf85_test: Pass, Slow # Issue 12029.
 html/js_function_getter_trust_types_test: Skip # --trust-type-annotations incompatible with --checked
 
-[ $compiler == dart2js && $csp && $minified ]
-collection/list_test: RuntimeError
-
 [ $compiler == dart2js && $csp && ($runtime == chrome || $runtime == chromeOnAndroid || $runtime == ff || $runtime == safari) ]
 html/event_customevent_test: SkipByDesign
 html/js_array_test: SkipByDesign
@@ -492,14 +199,9 @@
 html/postmessage_structured_test: SkipByDesign
 
 [ $compiler == dart2js && !$csp && $minified ]
-html/async_test: RuntimeError
 html/audiobuffersourcenode_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/audiocontext_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/audioelement_test: RuntimeError
-html/b_element_test: RuntimeError
-html/blob_constructor_test: RuntimeError
 html/cache_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/callbacks_test: RuntimeError
 html/custom_element_method_clash_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/custom_element_name_clash_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/custom_elements_23127_test: Crash # Assertion failure: Cannot find value local(B2T.created#a) in (type_variable_local(B2T.T), local(C2T.created#a), local(C2T.created#b), local(C2T.created#c), BoxLocal(_box_0)) for j:constructor(C2T.created).
@@ -516,18 +218,6 @@
 html/element_dimensions_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/element_offset_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/element_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/element_test/_ElementList: RuntimeError
-html/element_test/attributes: RuntimeError
-html/element_test/children: RuntimeError
-html/element_test/click: RuntimeError
-html/element_test/constructors: RuntimeError
-html/element_test/eventDelegation: RuntimeError
-html/element_test/eventListening: RuntimeError
-html/element_test/functional: RuntimeError
-html/element_test/matches: RuntimeError
-html/element_test/position: RuntimeError
-html/element_test/queryAll: RuntimeError
-html/element_types_constructors1_test: RuntimeError
 html/element_types_constructors2_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/element_types_constructors3_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/element_types_constructors4_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
@@ -544,191 +234,57 @@
 html/element_types_shadow_test: RuntimeError # Issue 29922
 html/element_types_template_test: RuntimeError # Issue 29922
 html/element_types_track_test: RuntimeError # Issue 29922
-html/event_test: RuntimeError
-html/exceptions_test: RuntimeError
-html/fileapi_supported_test: RuntimeError
-html/filereader_test: RuntimeError
-html/filteredelementlist_test: RuntimeError
-html/fontface_test: RuntimeError
 html/form_data_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/form_data_test/functional: RuntimeError
-html/form_data_test/supported: RuntimeError
-html/form_element_test: RuntimeError
-html/gamepad_test: RuntimeError
-html/geolocation_test: RuntimeError
-html/hidden_dom_1_test: RuntimeError
-html/hidden_dom_2_test: RuntimeError
 html/history_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/history_test/history: RuntimeError
-html/history_test/supported_HashChangeEvent: RuntimeError
-html/history_test/supported_state: RuntimeError
-html/htmlcollection_test: RuntimeError
-html/htmlelement_test: RuntimeError
-html/htmloptionscollection_test: RuntimeError
 html/indexeddb_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/indexeddb_1_test/dynamic: RuntimeError
-html/indexeddb_1_test/supported: RuntimeError
-html/indexeddb_1_test/typed: RuntimeError
-html/input_element_constructor_test: RuntimeError
-html/input_element_date_test: RuntimeError
-html/input_element_datetime_test: RuntimeError
-html/input_element_email_test: RuntimeError
-html/input_element_month_test: RuntimeError
-html/input_element_number_test: RuntimeError
-html/input_element_range_test: RuntimeError
-html/input_element_search_test: RuntimeError
-html/input_element_tel_test: RuntimeError
-html/input_element_time_test: RuntimeError
-html/input_element_url_test: RuntimeError
-html/input_element_week_test: RuntimeError
-html/instance_of_test: RuntimeError
-html/isolates_test: RuntimeError
-html/js_dispatch_property_test: RuntimeError
-html/js_javascript_function_test: RuntimeError
 html/keyboard_event_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/localstorage_test: RuntimeError
-html/location_test: RuntimeError
 html/mediasource_test: RuntimeError, Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/mouse_event_test: RuntimeError
 html/mutationobserver_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/native_gc_test: RuntimeError
-html/navigator_test: RuntimeError
 html/node_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/node_validator_important_if_you_suppress_make_the_bug_critical_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/notification_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/performance_api_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/query_test: RuntimeError
-html/queryall_test: RuntimeError
 html/range_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/request_animation_frame_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/rtc_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/selectelement_test: RuntimeError
 html/shadow_dom_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/shadowroot_test: RuntimeError
-html/storage_test: RuntimeError
-html/streams_test: RuntimeError
 html/svg_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/svgelement_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/table_test: RuntimeError
-html/text_event_test: RuntimeError
-html/track_element_constructor_test: RuntimeError
-html/transferables_test: RuntimeError
 html/transition_event_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/trusted_html_tree_sanitizer_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/typed_arrays_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/typed_arrays_2_test: RuntimeError
-html/typed_arrays_3_test: RuntimeError
-html/typed_arrays_4_test: RuntimeError
-html/typed_arrays_5_test: RuntimeError
-html/typed_arrays_arraybuffer_test: RuntimeError
-html/typed_arrays_dataview_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
-html/typed_arrays_simd_test: RuntimeError
-html/typing_test: RuntimeError
-html/unknownelement_test: RuntimeError
-html/uri_test: RuntimeError
-html/url_test: RuntimeError
 html/webgl_extensions_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/websocket_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/websql_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/wheelevent_test: RuntimeError
-html/window_eq_test: RuntimeError
-html/window_mangling_test: RuntimeError
-html/window_nosuchmethod_test: RuntimeError
 
 [ $compiler == dart2js && $host_checked ]
 html/custom/mirrors_2_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
 html/custom/mirrors_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
 html/indexeddb_3_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
 html/indexeddb_5_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
-html/js_array_test: CompileTimeError
-html/js_dispatch_property_test: CompileTimeError
 html/js_function_getter_test/call getter as function: Crash # FileSystemException(uri=file:///usr/local/google/home/efortuna/dart2/sdk/sdk/lib/_internal/dart2js_platform.dill; message=Error reading 'sdk/lib/_internal/dart2js_platform.dill'  (No such file or directory))
-html/js_function_getter_trust_types_test: CompileTimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
 html/js_typed_interop_side_cast_exp_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
-html/js_typed_interop_test: CompileTimeError
 
 [ $compiler == dart2js && $ie ]
 html/fontface_loaded_test: RuntimeError # FontFace polyfill?
 html/fontface_test: Fail # Fontface not supported on ie
-html/interactive_media_test: RuntimeError
 
 [ $compiler == dart2js && $minified ]
-html/audiobuffersourcenode_test/functional: RuntimeError
-html/audiobuffersourcenode_test/supported: RuntimeError
-html/audiocontext_test/supported: RuntimeError
-html/cache_test/ApplicationCache: RuntimeError
-html/cache_test/supported: RuntimeError
 html/canvas_pixel_array_type_alias_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/canvas_pixel_array_type_alias_test/basic: RuntimeError
-html/canvas_pixel_array_type_alias_test/typed_data: RuntimeError
-html/canvas_pixel_array_type_alias_test/types1: RuntimeError
-html/canvas_pixel_array_type_alias_test/types2: RuntimeError
 html/canvas_pixel_array_type_alias_test/types2_runtimeTypeName: Fail, OK # Issue 12605
 html/custom/mirrors_2_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/custom/mirrors_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/custom_elements_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/element_classes_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/element_offset_test/offset: RuntimeError
-html/element_test/ElementList: RuntimeError
-html/element_types_constructors2_test/constructors: RuntimeError
-html/element_types_constructors3_test/constructors: RuntimeError
-html/element_types_constructors4_test/constructors: RuntimeError
-html/element_types_constructors5_test/constructors: RuntimeError
-html/element_types_constructors6_test/constructors: RuntimeError
-html/element_types_constructors6_test/ul: RuntimeError
 html/element_types_keygen_test: RuntimeError # Issue 29922
-html/event_customevent_test: RuntimeError
-html/file_sample_test: RuntimeError
-html/fileapi_entry_test: RuntimeError
-html/indexeddb_1_test/functional: RuntimeError
-html/indexeddb_2_test: RuntimeError
-html/indexeddb_3_test: RuntimeError
-html/indexeddb_4_test: RuntimeError
-html/indexeddb_5_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_tests: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_dart_to_string_test: RuntimeError
-html/js_function_getter_test: CompileTimeError
-html/js_function_getter_test/call getter as function: RuntimeError
 html/js_function_getter_trust_types_test: Crash # NoSuchMethodError: Class 'InterfaceType' has no instance getter 'isObject'.
-html/js_function_getter_trust_types_test: CompileTimeError
-html/js_identity_test: RuntimeError
-html/js_interop_1_test: RuntimeError
-html/js_interop_constructor_name_div_test: RuntimeError
-html/js_interop_constructor_name_method_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_transferrables_test: RuntimeError
 html/js_typed_interop_bind_this_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/js_typed_interop_callable_object_test: CompileTimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
-html/js_typed_interop_default_arg_test/none: CompileTimeError
 html/js_typed_interop_side_cast_exp_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/js_typed_interop_test: CompileTimeError
-html/js_typed_interop_type1_test/01: RuntimeError
-html/js_typed_interop_type1_test/none: RuntimeError
-html/js_typed_interop_type3_test/01: RuntimeError
-html/js_typed_interop_type3_test/02: RuntimeError
-html/js_typed_interop_type3_test/none: RuntimeError
-html/js_typed_interop_type_test: RuntimeError
 html/js_typed_interop_window_property_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/js_util_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/media_stream_test: RuntimeError, Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/mirrors_js_typed_interop_test: RuntimeError
 html/postmessage_structured_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 html/speechrecognition_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/trusted_html_tree_sanitizer_test/not_create_document_fragment: RuntimeError
-html/trusted_html_tree_sanitizer_test/untrusted: RuntimeError
-html/typed_arrays_1_test/arrays: RuntimeError
-html/typed_arrays_1_test/supported: RuntimeError
 html/webgl_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
 
 [ $compiler == dart2js && ($runtime == chrome || $runtime == ff) ]
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index dd4bbaa..b3c2a53 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -3,48 +3,28 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dartdevc ]
-html/element_types_keygen_test: CompileTimeError # Chrome 57 keygen removed
-html/mediasource_test: RuntimeError # Issue 29922
-html/xhr_test: Pass, Slow
-
-[ $compiler == dartdevk ]
-async/slow_consumer_test: CompileTimeError
+html/xhr_test: Slow
 
 [ $runtime == chrome && ($compiler == dartdevc || $compiler == dartdevk) ]
-html/element_animate_test/timing_dict: RuntimeError # Issue 29922
-html/element_types_keygen_test: CompileTimeError # Issue 29055
 html/js_dispatch_property_test: Skip # Timeout Issue 31030
 
 [ $system == linux && ($compiler == dartdevc || $compiler == dartdevk) ]
 html/interactive_geolocation_test: Skip # Requires allowing geo location.
 
 [ $system == macos && ($compiler == dartdevc || $compiler == dartdevk) ]
-html/client_rect_test: Pass, RuntimeError # Issue 31019
-html/css_test: Pass, RuntimeError # Issue 31019
-html/fileapi_entry_test: Pass, RuntimeError # Issue 31019
 html/interactive_media_test: Skip # Requires interactive camera, microphone permissions.
 
 [ $system == windows && ($compiler == dartdevc || $compiler == dartdevk) ]
 html/xhr_test: Skip # Times out. Issue 21527
 
 [ $compiler == dartdevc || $compiler == dartdevk ]
-async/future_or_bad_type_test/implements: RuntimeError # Issue 29922
-async/future_or_bad_type_test/none: RuntimeError # Issue 29922
-async/future_test: RuntimeError # Issue 29922
-async/slow_consumer_test: Pass, Timeout # Issue 29922
-async/stream_distinct_test: RuntimeError # Issue 29922
-async/timer_not_available_test: RuntimeError
-convert/base64_test/01: Fail, OK # Uses bit-wise operations to detect invalid values. Some large invalid values accepted by DDC/dart2js.
-convert/chunked_conversion_utf88_test: Slow, Pass
-convert/json_utf8_chunk_test: Slow, Pass
-convert/streamed_conversion_json_utf8_encode_test: Pass, Timeout # Issue 29922
-convert/streamed_conversion_utf8_decode_test: Slow, Pass, Timeout # Issue 29922
-convert/utf85_test: Slow, Pass
-html/async_test: RuntimeError # Issue 29922
+convert/chunked_conversion_utf88_test: Slow
+convert/json_utf8_chunk_test: Slow
+convert/streamed_conversion_utf8_decode_test: Slow # Issue 29922
+convert/utf85_test: Slow
 html/callback_list_test: Skip # Test requires user interaction to accept permissions.
 html/custom/attribute_changed_callback_test: Skip # Issue 31577
 html/custom/constructor_calls_created_synchronously_test: Skip # Issue 31577
-html/custom/created_callback_test: RuntimeError
 html/custom/created_callback_test: Skip # Issue 31577
 html/custom/document_register_basic_test: Skip # Issue 31577
 html/custom/document_register_template_test: Skip # Issue 31577
@@ -58,45 +38,12 @@
 html/custom/document_register_type_extensions_test/single-parameter createElement: Skip # Issue 31577
 html/custom/element_upgrade_test: Skip # Issue 31577
 html/custom/entered_left_view_test: Skip # Issue 31577
-html/custom/js_custom_test: Crash # Issue 29922
 html/custom/mirrors_2_test: Skip # Issue 31577
-html/custom/mirrors_test: Crash # Issue 29922
-html/custom/regress_194523002_test: Crash # Issue 29922
 html/custom_element_method_clash_test: Skip # Issue 29922
 html/custom_element_name_clash_test: Skip # Issue 29922
 html/custom_elements_23127_test: Skip # Issue 29922
 html/custom_elements_test: Skip # Issue 29922
-html/element_classes_test: RuntimeError # Issue 29922
-html/isolates_test: RuntimeError # Issue 29922
-html/js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue 29922
-html/js_typed_interop_side_cast_exp_test/01: RuntimeError # Requires --experimental-trust-js-interop-type-annotations flag.
-html/js_typed_interop_type3_test/*: RuntimeError # Issue 30947
-html/js_typed_interop_type_test: RuntimeError # Issue 30947
-html/js_util_test: RuntimeError # Issue 29922
-html/media_stream_test: RuntimeError # Issue 29922
 html/notification_permission_test: Skip # Issue 32002
-html/transition_event_test: Pass, RuntimeError, Timeout # Issue 29922, this test seems flaky
-html/webgl_extensions_test: RuntimeError # Issue 31017
-html/worker_api_test: RuntimeError # Issue 29922
 isolate/*: SkipByDesign # No support for dart:isolate in dart4web (http://dartbug.com/30538)
-js/null_test: RuntimeError # Issue 30652
-math/double_pow_test: RuntimeError # Issue 29922
-math/double_pow_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-math/random_big_test: RuntimeError # Issue 29922
 mirrors/*: SkipByDesign # Mirrors not supported on web in Dart 2.0.
-mirrors/private_types_test: RuntimeError # Issue 29922
-mirrors/reflect_runtime_type_test: RuntimeError # Issue 29922
-mirrors/reflect_uninstantiated_class_test: RuntimeError # Issue 29922
-mirrors/reflected_type_function_type_test: RuntimeError # Issue 29922
-mirrors/reflected_type_special_types_test: RuntimeError # Issue 29922
-mirrors/reflected_type_typedefs_test: RuntimeError # Issue 29922
-mirrors/reflected_type_typevars_test: RuntimeError # Issue 29922
-mirrors/regress_14304_test: RuntimeError # Issue 29922
 profiler/metrics_num_test: Skip # Because of an int / double type test.
-typed_data/int32x4_arithmetic_test/int64: RuntimeError # Issue 29922
-typed_data/int32x4_arithmetic_test/int64: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/int32x4_arithmetic_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/int64_list_load_store_test: RuntimeError # Issue 29922
-typed_data/int64_list_load_store_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/typed_data_hierarchy_int64_test: RuntimeError # Issue 29922
-typed_data/unmodifiable_typed_data_test: RuntimeError # Issue 10275
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 531e3d4..23463b5 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -4,53 +4,31 @@
 # Sections in this file should contain "$compiler == dartk" or
 # "$compiler == dartkp".
 
-convert/streamed_conversion_json_utf8_decode_test: Pass, Slow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
+convert/streamed_conversion_json_utf8_decode_test: Slow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
 isolate/ping_pause_test: Skip # Issue https://dartbug.com/37787
 
-[ $builder_tag == asan ]
-isolate/non_fatal_exception_in_timer_callback_test: Pass, Fail # Issue 34724
-mirrors/dynamic_load_test: Fail # Issue 32187
-
 [ $compiler == dartkb ]
-convert/streamed_conversion_json_utf8_decode_test: Pass, Timeout # Please triage.
-isolate/isolate_complex_messages_test: Pass, Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
-isolate/mandel_isolate_test: Pass, Timeout # Please triage.
-isolate/spawn_uri_exported_main_test: Pass, RuntimeError # Please triage: Expect.fail('Isolate was not spawned successfully.')
-mirrors/library_uri_io_test: RuntimeError # Platform.script points to dill file.
+isolate/isolate_complex_messages_test: Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
 
 [ $compiler == fasta ]
 html/*: Skip # TODO(ahe): Make dart:html available.
 js/*: Skip # TODO(ahe): Make dart:js available.
 
-[ $fasta ]
-async/future_or_type_test: CompileTimeError # Issue 34626
-mirrors/generic_f_bounded_mixin_application_test: CompileTimeError # Issue 34613
-mirrors/redirecting_factory_test/01: CompileTimeError # Issue 34714
-mirrors/redirecting_factory_test/none: CompileTimeError # Issue 34714
-
 [ $arch == simdbc64 && $hot_reload_rollback ]
 convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
 
-[ $arch == x64 && $builder_tag == asan && $compiler == dartk ]
-mirrors/dynamic_load_test: Fail # Memory leak (issue 34724)
-
 [ $arch == x64 && $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
 mirrors/invocation_fuzz_test: Skip # Because it times out, issue 29439.
 
 [ $arch == x64 && ($hot_reload || $hot_reload_rollback) ]
-convert/base64_test/01: Pass, Crash # http://dartbug.com/35948
-isolate/int32_length_overflow_test: Timeout # Issue 35733
-
-[ $builder_tag == obfuscated && $compiler == dartkp ]
-collection/list_test: RuntimeError # Issue 34911
+convert/base64_test/01: Crash # http://dartbug.com/35948
 
 [ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
-isolate/unresolved_ports_test: CompileTimeError, Pass, Timeout # Fails to compile on opt counter builder (#31838)
-mirrors/invocation_fuzz_test/emptyarray: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/false: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/none: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/smi: Crash, RuntimeError, Fail, Pass # Crashes on opt counter builder (#31838)
-mirrors/invocation_fuzz_test/string: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/emptyarray: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/false: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/none: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/smi: Crash # Crashes on opt counter builder (#31838)
+mirrors/invocation_fuzz_test/string: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
 
 [ $compiler == app_jitk && ($mode == product || $mode == release) ]
 isolate/spawn_uri_nested_vm_test: Skip # Timeout, Issue 33385
@@ -60,7 +38,6 @@
 
 # ===== dartkp + dart_precompiled status lines =====
 [ $compiler == dartkp && $runtime == dart_precompiled ]
-async/slow_consumer2_test: RuntimeError # Issue 31402 (Invocation arguments)
 html/*: SkipByDesign # dart:html not supported on VM.
 isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
 isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
@@ -73,69 +50,24 @@
 [ $mode == debug && $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
 isolate/message3_test/constList_identical: Skip # Timeout
 
-[ $runtime == vm && $checked && ($compiler == dartk || $compiler == dartkb) ]
-mirrors/redirecting_factory_different_type_test/none: RuntimeError # Issue 28424
-
 # ===== dartk + vm status lines =====
 [ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
-async/slow_consumer2_test: CompileTimeError # Issue 31402 (Invocation arguments)
 html/*: SkipByDesign # dart:html not supported on VM.
 isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
 isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
 isolate/issue_21398_parent_isolate2_test/01: Skip # Times out. Deferred loading kernel issue 28335.
 isolate/static_function_test: Skip # Times out. Issue 31855. CompileTimeError. Issue 31402
-mirrors/class_declarations_test/01: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/class_declarations_test/none: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/constructor_private_name_test: RuntimeError # Issue 33345 - Incorrect qualified symbol literal from kernel reader
-mirrors/constructors_test: CompileTimeError # Issue 31402 (Invocation arguments)
-mirrors/dart2js_mirrors_test: RuntimeError # 31916
-mirrors/enum_test: RuntimeError # Issue 31402 (Invocation arguments)
 mirrors/invocation_fuzz_test: Crash
-mirrors/library_declarations_test/none: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/library_exports_hidden_test: RuntimeError # Issue 33098
-mirrors/library_exports_shown_test: RuntimeError # Issue 33098
-mirrors/library_import_deferred_loading_test: RuntimeError # Issue 33098
-mirrors/library_imports_deferred_test: RuntimeError # Issue 33098
-mirrors/library_imports_hidden_test: RuntimeError # Issue 33098
-mirrors/library_imports_metadata_test: RuntimeError # Issue 33098
-mirrors/library_imports_prefixed_show_hide_test: RuntimeError # Issue 33098
-mirrors/library_imports_prefixed_test: RuntimeError # Issue 33098
-mirrors/library_imports_shown_test: RuntimeError # Issue 33098
 mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
-mirrors/method_mirror_source_line_ending_test: RuntimeError # Issue 33478
-mirrors/method_mirror_source_test: RuntimeError # Issue 33041
-mirrors/mirrors_nsm_mismatch_test: CompileTimeError # Issue 31533
-mirrors/mirrors_nsm_test/dart2js: CompileTimeError # Issue 31533
-mirrors/mirrors_nsm_test/none: CompileTimeError # Issue 31533
 mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
-mirrors/mixin_application_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/mixin_members_test: CompileTimeError # Issue 31402 (Invocation arguments)
 mirrors/native_class_test: SkipByDesign # Imports dart:html
-mirrors/operator_test: CompileTimeError # Issue 31402 (Invocation arguments)
-mirrors/other_declarations_location_test: RuntimeError # Issue 33325 (no source positions for type parameters).
-mirrors/parameter_of_mixin_app_constructor_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/private_symbol_test: RuntimeError # Issue 33326 - CFE/kernel invalid typedef substitution
-mirrors/private_types_test: RuntimeError # Issue 33326 - CFE/kernel invalid typedef substitution
-mirrors/repeated_private_anon_mixin_app_test: RuntimeError # Mangled mixin application class name
-mirrors/static_members_easier_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/static_members_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/symbol_validation_test/01: RuntimeError # Issue 31537
-mirrors/symbol_validation_test/none: RuntimeError # Issue 31537
-mirrors/typedef_deferred_library_test: CompileTimeError # Deferred loading kernel issue 28335.
 
 [ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
 isolate/illegal_msg_function_test: Skip # Timeout
 isolate/pause_test: Skip # Timeout
 
-# Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
-# are to be triaged.  Isolate tests are skipped on purpose due to the usage of
-# batch mode.
-[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-mirrors/library_uri_io_test: RuntimeError # Please triage.
-
 [ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
-isolate/mandel_isolate_test: Pass, Timeout, RuntimeError # Test can time out which results in runtime error
-isolate/message4_test: Pass, Timeout, Crash # Timeout and sporadic crash (issue 33824)
+isolate/message4_test: Crash # Timeout and sporadic crash (issue 33824)
 mirrors/dynamic_load_test: Crash
 mirrors/library_uri_io_test: Skip # Timeout
 mirrors/library_uri_package_test: Skip # Timeout
@@ -144,8 +76,5 @@
 html/*: SkipByDesign
 js/*: SkipByDesign
 
-[ $compiler == dartk || $compiler == dartkb ]
-async/slow_consumer2_test: RuntimeError # Issue 31402 (Invocation arguments)
-
 [ $hot_reload || $hot_reload_rollback ]
 isolate/issue_6610_test: Skip # Sources are looked up on every reload request.
diff --git a/tests/lib_2/lib_2_vm.status b/tests/lib_2/lib_2_vm.status
index 869e7c8..305c371 100644
--- a/tests/lib_2/lib_2_vm.status
+++ b/tests/lib_2/lib_2_vm.status
@@ -79,9 +79,6 @@
 mirrors/library_uri_io_test: RuntimeError
 mirrors/library_uri_package_test: RuntimeError
 
-[ $runtime == vm && $no_preview_dart_2 ]
-async/async_no_await_zones_test: RuntimeError # not supported in Dart 1 mode.
-
 [ $runtime == vm && ($arch == simarm || $arch == simarmv5te || $arch == simarmv6) ]
 convert/utf85_test: Skip # Pass, Slow Issue 12644.
 
diff --git a/tests/lib_2/mirrors/regress_38035_test.dart b/tests/lib_2/mirrors/regress_38035_test.dart
new file mode 100644
index 0000000..4e6c25a
--- /dev/null
+++ b/tests/lib_2/mirrors/regress_38035_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/38035.
+//
+// Verifies that static tear-off has correct information about argument types.
+
+import 'package:expect/expect.dart';
+import 'dart:mirrors';
+
+class A {
+  static bool _defaultCheck([dynamic e]) => true;
+}
+
+main() {
+  Expect.equals('([dynamic]) -> dart.core.bool',
+      MirrorSystem.getName(reflect(A._defaultCheck).type.simpleName));
+}
diff --git a/tests/modular/extension_methods/def.dart b/tests/modular/extension_methods/def.dart
new file mode 100644
index 0000000..665da3d8
--- /dev/null
+++ b/tests/modular/extension_methods/def.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {
+  int field;
+
+  Class(this.field);
+}
+
+extension Extension on Class {
+  int method() => this.field;
+
+  int get property => this.field;
+
+  void set property(int value) {
+    this.field = value;
+  }
+
+  int _privateMethod() => this.field;
+
+  static int staticField = 87;
+
+  static int staticMethod() => staticField;
+
+  static int get staticProperty => staticField;
+
+  static void set staticProperty(int value) {
+    staticField = value;
+  }
+}
+
+extension /*UnnamedExtension*/ on Class {
+  int method() => this.field + 1;
+}
+
+extension _PrivateExtension on Class {
+  int method() => this.field + 2;
+}
+
+class GenericClass<T> {
+  T field;
+
+  GenericClass(this.field);
+}
+
+extension GenericExtension<T> on GenericClass<T> {
+  T method() => this.field;
+
+  T get property => this.field;
+
+  void set property(T value) {
+    this.field = value;
+  }
+}
\ No newline at end of file
diff --git a/tests/modular/extension_methods/main.dart b/tests/modular/extension_methods/main.dart
new file mode 100644
index 0000000..760cc85
--- /dev/null
+++ b/tests/modular/extension_methods/main.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+import 'def.dart';
+
+main() {
+  testExplicitAccess(new Class(42));
+  testImplicitAccess(new Class(87));
+  testStaticAccess();
+  testExplicitGenericAccess(new GenericClass<String>('foo'), 'bar');
+  testImplicitGenericAccess(new GenericClass<String>('baz'), 'boz');
+}
+
+testExplicitAccess(Class c) {
+  Expect.equals(c.field, Extension(c).method());
+  Expect.equals(c.field, Extension(c).property);
+  Expect.equals(123, Extension(c).property = 123);
+  var f = Extension(c).method;
+  Expect.equals(c.field, f());
+}
+
+testImplicitAccess(Class c) {
+  Expect.equals(c.field, c.method());
+  Expect.equals(c.field, c.property);
+  Expect.equals(123, c.property = 123);
+  var f = c.method;
+  Expect.equals(c.field, f());
+}
+
+testStaticAccess() {
+  Expect.equals(Extension.staticField, Extension.staticMethod());
+  Expect.equals(Extension.staticField, Extension.staticProperty);
+  Expect.equals(123, Extension.staticProperty = 123);
+}
+
+testExplicitGenericAccess<T>(GenericClass<T> c, T value) {
+  Expect.equals(c.field, GenericExtension<T>(c).method());
+  Expect.equals(c.field, GenericExtension<T>(c).property);
+  Expect.equals(value, GenericExtension<T>(c).property = value);
+  var f = GenericExtension<T>(c).method;
+  Expect.equals(c.field, f());
+}
+
+testImplicitGenericAccess<T>(GenericClass<T> c, T value) {
+  Expect.equals(c.field, c.method());
+  Expect.equals(c.field, c.property);
+  Expect.equals(value, c.property = value);
+  var f = c.method;
+  Expect.equals(c.field, f());
+}
diff --git a/tests/modular/extension_methods/modules.yaml b/tests/modular/extension_methods/modules.yaml
new file mode 100644
index 0000000..854c44f
--- /dev/null
+++ b/tests/modular/extension_methods/modules.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+dependencies:
+  main: [def, expect]
+flags: 
+  - extension-methods
\ No newline at end of file
diff --git a/tests/standalone_2/fragmentation_typed_data_test.dart b/tests/standalone_2/fragmentation_typed_data_test.dart
index 470aaad..0d00fb2 100644
--- a/tests/standalone_2/fragmentation_typed_data_test.dart
+++ b/tests/standalone_2/fragmentation_typed_data_test.dart
@@ -13,12 +13,17 @@
 // VMOptions=--concurrent_mark --use_compactor
 // VMOptions=--concurrent_mark --use_compactor --force_evacuation
 
+import 'dart:io';
 import 'dart:typed_data';
 
 main() {
+  // We have less memory available on the Android testing devices, and if we
+  // allocate to much the kernel may summarily terminate us.
+  final double factor = Platform.isAndroid ? 0.5 : 1.0;
+
   final List<List> arrays = [];
   // Fill up heap with alternate large-small items.
-  for (int i = 0; i < 500000; i++) {
+  for (int i = 0; i < 500000 * factor; i++) {
     arrays.add(new Uint32List(260));
     arrays.add(new Uint32List(1));
   }
@@ -27,7 +32,7 @@
     arrays[i] = null;
   }
   // Allocate a lot of large items which don't fit in the gaps created above.
-  for (int i = 0; i < 600000; i++) {
+  for (int i = 0; i < 600000 * factor; i++) {
     arrays.add(new Uint32List(300));
   }
 }
diff --git a/tests/standalone_2/io/file_system_watcher_test.dart b/tests/standalone_2/io/file_system_watcher_test.dart
index 492379a..14eb5f9 100644
--- a/tests/standalone_2/io/file_system_watcher_test.dart
+++ b/tests/standalone_2/io/file_system_watcher_test.dart
@@ -141,8 +141,7 @@
   var watcher = dir.watch(events: 0);
 
   asyncStart();
-  var sub;
-  sub = watcher.listen((event) {
+  watcher.listen((event) {
     if (event is FileSystemDeleteEvent) {
       Expect.isTrue(event.path == dir.path);
     }
@@ -298,9 +297,8 @@
   var watcher = dir2.watch();
 
   asyncStart();
-  var sub;
   bool gotDelete = false;
-  sub = watcher.listen((event) {
+  watcher.listen((event) {
     if (event is FileSystemDeleteEvent) {
       Expect.isTrue(event.path.endsWith('dir'));
       gotDelete = true;
@@ -319,42 +317,56 @@
   // happens in a very short period of time the modifying event will be missed before the
   // stream listen has been set up and the watcher will hang forever.
   // Bug: https://github.com/dart-lang/sdk/issues/37233
+  // Bug: https://github.com/dart-lang/sdk/issues/37909
   asyncStart();
   ReceivePort receivePort = ReceivePort();
-  await Isolate.spawn(modifyFiles, receivePort.sendPort);
+  Completer<bool> exiting = Completer<bool>();
 
-  await for (var object in receivePort) {
-    if (object == 'end') {
-      receivePort.close();
-      break;
+  Directory dir;
+  Completer<bool> modificationEventReceived = Completer<bool>();
+
+  StreamSubscription receiverSubscription;
+  SendPort workerSendPort;
+  receiverSubscription = receivePort.listen((object) async {
+    if (object == 'modification_started') {
+      var watcher = dir.watch();
+      var subscription;
+      // Wait for event and check the type
+      subscription = watcher.listen((data) async {
+        if (data is FileSystemModifyEvent) {
+          Expect.isTrue(data.path.endsWith('file'));
+          await subscription.cancel();
+          modificationEventReceived.complete(true);
+        }
+      });
+      return;
     }
-    var sendPort = object[0];
-    var path = object[1];
-    var dir = new Directory(path);
+    if (object == 'end') {
+      await receiverSubscription.cancel();
+      exiting.complete(true);
+      return;
+    }
+    // init event
+    workerSendPort = object[0];
+    dir = new Directory(object[1]);
+  });
 
-    sendPort.send('start');
-    // Delay some time to ensure that watcher is created when modification is running consistently.
-    await Future.delayed(Duration(milliseconds: 10));
-    var watcher = dir.watch();
-    var subscription;
+  Completer<bool> workerExitedCompleter = Completer();
+  RawReceivePort exitReceivePort = RawReceivePort((object) { workerExitedCompleter.complete(true); });
+  RawReceivePort errorReceivePort = RawReceivePort((object) { print('worker errored: $object'); });
+  await Isolate.spawn(modifyFiles, receivePort.sendPort, onExit: exitReceivePort.sendPort, onError: errorReceivePort.sendPort);
 
-    // Wait for event and check the type
-    subscription = watcher.listen((data) {
-      if (data is FileSystemModifyEvent) {
-        Expect.isTrue(data.path.endsWith('file'));
-        subscription.cancel();
-      }
-    });
+  await modificationEventReceived.future;
+  workerSendPort.send('end');
 
-    // Create a file to signal modifier isolate to stop modification and clean up temp directory.
-    var file = new File(join(dir.path, 'EventReceived'));
-    file.createSync();
-    sendPort.send('end');
-  }
+  await exiting.future;
+  await workerExitedCompleter.future;
+  exitReceivePort.close();
+  errorReceivePort.close();
   asyncEnd();
 }
 
-void modifyFiles(SendPort sendPort) {
+void modifyFiles(SendPort sendPort) async {
   // Send sendPort back to listen for modification signal.
   ReceivePort receivePort = ReceivePort();
   var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
@@ -362,25 +374,30 @@
   // Create file within the directory and keep modifying.
   var file = new File(join(dir.path, 'file'));
   file.createSync();
+  bool done = false;
   var subscription;
-  sendPort.send([receivePort.sendPort, dir.path]);
-  subscription = receivePort.listen((data) {
-    if (data == 'end') {
-      // Clean up the directory and files
-      dir.deleteSync(recursive: true);
-      sendPort.send('end');
-      subscription.cancel();
-    } else {
-      // This signal file is created once watcher isolate receives the event.
-      var signal = new File(join(dir.path, 'EventReceived'));
-      while (!signal.existsSync()) {
-        // Start modifying the file continuously before watcher start watching.
-        for (int i = 0; i < 100; i++) {
-          file.writeAsStringSync('a');
-        }
-      }
+  subscription = receivePort.listen((object) async {
+    if (object == 'end') {
+      await subscription.cancel();
+      done = true;
     }
   });
+  sendPort.send([receivePort.sendPort, dir.path]);
+  bool notificationSent = false;
+  while(!done) {
+    // Start modifying the file continuously before watcher start watching.
+    for (int i = 0; i < 100; i++) {
+      file.writeAsStringSync('a');
+    }
+    if (!notificationSent) {
+      sendPort.send('modification_started');
+      notificationSent = true;
+    }
+    await Future.delayed(Duration());
+  }
+  // Clean up the directory and files
+  dir.deleteSync(recursive: true);
+  sendPort.send('end');
 }
 
 void main() {
diff --git a/tests/standalone_2/io/http_linklocal_ipv6_test.dart b/tests/standalone_2/io/http_linklocal_ipv6_test.dart
new file mode 100644
index 0000000..ea4e54d
--- /dev/null
+++ b/tests/standalone_2/io/http_linklocal_ipv6_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+import 'dart:io';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+
+void main() {
+  // A virtual tun/tap interface should be created with following instrutctions:
+  // Create an interface with name [tap0],
+  //    sudo ip tuntap add name [tap0] mode tap
+  // Assign an ipv6 address [fe80:1::1],
+  //    sudo ip -6 addr add dev [tap0] [fe80:1::1] scope link nodad
+  // Check for virtual interface with ipv6 set,
+  //    ip address show
+  asyncStart();
+  try {
+    // Make sure the address here is the same as what it shows in "ip address show"
+    var ipv6 = 'fe80:1::10%tap0';
+    HttpServer.bind(ipv6, 0).then((server) {
+      server.listen((request) {
+        var timer = new Timer.periodic(const Duration(milliseconds: 0), (_) {
+          request.response
+              .write('data:${new DateTime.now().millisecondsSinceEpoch}\n\n');
+        });
+        request.response.done.whenComplete(() {
+          timer.cancel();
+        }).catchError((_) {});
+      });
+
+      var client = new HttpClient();
+      client
+          .getUrl(Uri.parse("http://[${ipv6}]:${server.port}"))
+          .then((request) => request.close())
+          .then((response) {
+        print(
+            'reponse: status code: ${response.statusCode}, reason: ${response.reasonPhrase}');
+        int bytes = 0;
+        response.listen((data) {
+          bytes += data.length;
+          if (bytes > 100) {
+            client.close(force: true);
+          }
+        }, onError: (error) {
+          server.close();
+        });
+      });
+      asyncEnd();
+    });
+  } catch (e) {
+    Expect.fail('SocketException: $e');
+    asyncEnd();
+  }
+}
diff --git a/tests/standalone_2/standalone_2.status b/tests/standalone_2/standalone_2.status
index 6754a30..7f28264 100644
--- a/tests/standalone_2/standalone_2.status
+++ b/tests/standalone_2/standalone_2.status
@@ -5,6 +5,7 @@
 # Tests using the multitest feature where failure is expected should *also* be
 # listed in tests/lib/analyzer/analyze_tests.status without the "standalone"
 # prefix.
+io/http_linklocal_ipv6_test: SkipByDesign # This needs manual test.
 io/non_utf8_directory_test: Skip # Issue 33519. Temp files causing bots to go purple.
 io/non_utf8_file_test: Skip # Issue 33519. Temp files causing bots to go purple.
 io/non_utf8_link_test: Skip # Issue 33519. Temp files causing bots to go purple.
@@ -93,9 +94,6 @@
 io/socket_connect_stream_data_close_cancel_test: Pass, Timeout # Issue 27453
 io/socket_many_connections_test: Skip # This test fails with "Too many open files" on the Mac OS buildbot. This is expected as MacOS by default runs with a very low number of allowed open files ('ulimit -n' says something like 256).
 
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
 [ $arch == arm || $arch == arm64 || $runtime != vm || $mode == debug && $system == windows ]
 fragmentation_test: Skip
 
diff --git a/tests/standalone_2/standalone_2_analyzer.status b/tests/standalone_2/standalone_2_analyzer.status
index df9b617..fa699b4 100644
--- a/tests/standalone_2/standalone_2_analyzer.status
+++ b/tests/standalone_2/standalone_2_analyzer.status
@@ -5,11 +5,4 @@
 [ $compiler == dart2analyzer ]
 deferred_transitive_import_error_test: Skip # Contains intentional errors.
 io/process_exit_negative_test: Skip
-package/scenarios/invalid/invalid_package_name_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/invalid_utf8_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/non_existent_packages_file_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/same_package_twice_test: Crash, OK # Analyzer exits on invalid package config
 
-[ $compiler == dart2analyzer && $system == windows ]
-package/scenarios/empty_packages_file/empty_packages_file_option_test: Crash, Pass # Issue 28645
-package/scenarios/packages_file_strange_formatting/empty_package_dir_test: Crash # Issue 28645
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index dc7698b..93f0fda 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -4,42 +4,21 @@
 # Sections in this file should contain "$compiler == dartk" or
 # "$compiler == dartkp".
 
-fragmentation_test: Pass, Slow # GC heavy
-io/process_sync_test: Pass, Slow # Spawns synchronously subprocesses in sequence.
-
-[ $builder_tag == asan ]
-io/file_test: Fail # Issue 34724
-io/http_server_response_test: Fail # Issue 34724
-io/process_sync_test: Pass, Fail # https://github.com/dart-lang/sdk/issues/34724
-io/signals_test: Fail # Issue 34724
-io/test_extension_fail_test: Fail # Issue 32187
+fragmentation_test: Slow # GC heavy
+io/process_sync_test: Slow # Spawns synchronously subprocesses in sequence.
 
 [ $compiler == dartkb ]
-io/dart_std_io_pipe_test: Pass, Timeout # Please triage
-io/platform_test: RuntimeError # Platform.script points to dill file.
 no_lazy_dispatchers_test: SkipByDesign # KBC interpreter doesn't support --no_lazy_dispatchers
 
-[ $compiler == dartkp ]
-io/arguments_test: Fail # Test harness passes runtime arguments to the compiler
-
 [ $system == android ]
 entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
 
 [ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
 io/file_lock_test: SkipSlow # Timeout
 
-[ $arch == ia32 && $compiler == dartk ]
-io/dart_std_io_pipe_test: Timeout, Pass # Issue 34723
-
 [ $arch == simarm64 && ($compiler == dartk || $compiler == dartkb) ]
 io/http_bind_test: Slow
 
-[ $arch == x64 && $builder_tag == asan && $compiler == dartk ]
-io/file_test: Fail # Memory leak (issue 34724)
-io/http_server_response_test: Fail # Memory leak (issue 34724)
-io/signals_test: Pass, RuntimeError # Issue 34734
-io/test_extension_fail_test: Fail # Memory leak (issue 34724)
-
 [ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
 map_insert_remove_oom_test: Skip # Heap limit too low.
 
@@ -66,7 +45,6 @@
 io/raw_datagram_socket_test: Skip # Flaky.
 io/raw_secure_server_closing_test: Skip # Flaky
 io/raw_socket_test: Crash
-io/secure_builtin_roots_test: Timeout, Pass # Times out on bots.
 io/secure_multiple_client_server_test: Skip # Flaky.
 io/secure_server_closing_test: Skip # Flaky.
 io/secure_server_socket_test: Skip # Flaky.
@@ -77,7 +55,6 @@
 io/web_socket_test: Skip # Flaky.
 map_insert_remove_oom_test: Skip # Heap limit too low.
 no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
-regress_29350_test/none: Pass # Issue 31537
 
 [ $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
 io/file_lock_test: Slow
@@ -93,14 +70,10 @@
 
 [ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
 no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
-regress_29350_test/none: Pass # Issue 31537
 
 [ $system == windows && ($compiler == dartk || $compiler == dartkb) ]
-io/compile_all_test: Pass, Fail # Possibly related to issue 32373
 io/dart_std_io_pipe_test: Slow
 io/secure_builtin_roots_test: Skip # Issues 32137 and 32138.
-io/test_extension_fail_test: RuntimeError, Pass # Issue 32137.
-io/test_extension_test: RuntimeError, Pass # Issue 32137.
 io/wait_for_event_isolate_test: Skip # Issues 32137 and 32138.
 map_insert_remove_oom_test: Skip # Heap limit too low.
 
@@ -116,12 +89,8 @@
 # are to be triaged.  Isolate tests are skipped on purpose due to the usage of
 # batch mode.
 [ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-io/directory_list_sync_test: Timeout, Pass # Please triage.
-io/file_blocking_lock_test: Pass, Crash # Please triage.
+io/file_blocking_lock_test: Crash # Please triage.
 io/file_lock_test: Slow
-io/platform_test: RuntimeError # Platform.script points to dill file.
-io/test_extension_fail_test: RuntimeError # Platform.script points to dill file.
-io/test_extension_test: RuntimeError # Platform.script points to dill file.
 map_insert_remove_oom_test: Skip # Heap limit too low.
 
 [ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
@@ -129,7 +98,6 @@
 io/http_advanced_test: Skip # Timeout
 io/http_auth_digest_test: Crash
 io/http_auth_test: Skip # Timeout
-io/http_basic_test: Pass, Timeout # Issue 28046
 io/http_proxy_advanced_test: Skip # Timeout
 io/http_read_test: Skip # Timeout
 io/pipe_server_test: Skip # Timeout
diff --git a/tools/VERSION b/tools/VERSION
index b56200c..e822ddc 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -31,9 +31,9 @@
 #
 CHANNEL dev
 MAJOR 2
-MINOR 5
+MINOR 6
 PATCH 0
-PRERELEASE 5
+PRERELEASE 0
 PRERELEASE_PATCH 0
-ABI_VERSION 11
-OLDEST_SUPPORTED_ABI_VERSION 11
+ABI_VERSION 14
+OLDEST_SUPPORTED_ABI_VERSION 13
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index fc840f3..f3543ce 100755
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -142,6 +142,10 @@
 
     # Functions for querying gs:// directories
 
+    def base_directory(self, revision):
+        return '%s/channels/%s/%s/%s' % (self.bucket, self.channel,
+                                         self.release_type, revision)
+
     def sdk_directory(self, revision):
         return self._variant_directory('sdk', revision)
 
@@ -164,8 +168,7 @@
         return self._variant_directory('misc', revision)
 
     def _variant_directory(self, name, revision):
-        return '%s/channels/%s/%s/%s/%s' % (self.bucket, self.channel,
-                                            self.release_type, revision, name)
+        return '%s/%s' % (self.base_directory(revision), name)
 
     # Functions for quering filenames
 
diff --git a/tools/bots/results.dart b/tools/bots/results.dart
index c42d828..1383b3b 100644
--- a/tools/bots/results.dart
+++ b/tools/bots/results.dart
@@ -131,10 +131,14 @@
 }
 
 Map<String, Map<String, dynamic>> createResultsMap(
-        List<Map<String, dynamic>> results) =>
-    new Map<String, Map<String, dynamic>>.fromIterable(results,
-        key: (dynamic result) =>
-            "${result["configuration"]}:${result["name"]}");
+    List<Map<String, dynamic>> results) {
+  Map<String, Map<String, dynamic>> result = {};
+  for (Map<String, dynamic> map in results) {
+    var key = "${map["configuration"]}:${map["name"]}";
+    result.putIfAbsent(key, () => map);
+  }
+  return result;
+}
 
 Map<String, Map<String, dynamic>> parseResultsMap(String contents) =>
     createResultsMap(parseResults(contents));
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 650f810..64de89d 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -596,7 +596,8 @@
     },
     {
       "builders": [
-        "vm-kernel-precomp-android-release-arm"
+        "vm-kernel-precomp-android-release-arm",
+        "vm-kernel-precomp-android-release-arm64"
       ],
       "meta": {
         "description": "This configuration is used by the vm precomp builders on Android."
@@ -1054,7 +1055,8 @@
             "--enable-asserts",
             "pkg/dev_compiler/bin/dartdevc.dart",
             "-k",
-            "-o=out/ReleaseX64/dartdevk.js",
+            "-o",
+            "out/ReleaseX64/dartdevk.js",
             "pkg/dev_compiler/bin/dartdevc.dart"
           ]
         }
@@ -1091,18 +1093,6 @@
             "lib_2",
             "dartdevc_native"
           ]
-        },
-        {
-          "name": "ddc kernel modular tests",
-          "script": "out/ReleaseX64/dart-sdk/bin/dart",
-          "testRunner": true,
-          "arguments": [
-            "pkg/dev_compiler/test/modular_suite.dart",
-            "--configuration-name",
-            "dartdevk-${system}-release",
-            "--verbose",
-            "--use-sdk"
-          ]
         }
       ]
     },
@@ -1120,18 +1110,6 @@
           "arguments": ["dart2js_bot", "dartdevc_test"]
         },
         {
-          "name": "ddc tests",
-          "arguments": [
-            "-ndartdevc-checked-mac-release-chrome",
-            "language_2",
-            "corelib_2",
-            "lib_2",
-            "dartdevc_native"
-          ],
-          "shards": 1,
-          "fileset": "dart2js"
-        },
-        {
           "name": "ddc kernel tests",
           "arguments": [
             "-ndartdevk-checked-mac-release-chrome",
@@ -1154,14 +1132,6 @@
           ]
         },
         {
-          "name": "ddc sourcemap tests",
-          "script": "xcodebuild/ReleaseX64/dart",
-          "arguments": [
-            "pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart",
-            "-rnone"
-          ]
-        },
-        {
           "name": "ddk sourcemap tests",
           "script": "xcodebuild/ReleaseX64/dart",
           "arguments": [
@@ -1170,14 +1140,6 @@
           ]
         },
         {
-          "name": "ddc sourcemap stacktrace tests",
-          "script": "xcodebuild/ReleaseX64/dart",
-          "arguments": [
-            "pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart",
-            "-rnone"
-          ]
-        },
-        {
           "name": "ddk sourcemap stacktrace tests",
           "script": "xcodebuild/ReleaseX64/dart",
           "arguments": [
@@ -1194,23 +1156,14 @@
           ]
         },
         {
-          "name": "ddc self host test",
-          "script": "xcodebuild/ReleaseX64/dart-sdk/bin/dart",
-          "arguments": [
-            "--enable-asserts",
-            "pkg/dev_compiler/bin/dartdevc.dart",
-            "-o=xcodebuild/ReleaseX64/dartdevc.js",
-            "pkg/dev_compiler/bin/dartdevc.dart"
-          ]
-        },
-        {
           "name": "ddk self host test",
           "script": "xcodebuild/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
             "--enable-asserts",
             "pkg/dev_compiler/bin/dartdevc.dart",
             "-k",
-            "-o=xcodebuild/ReleaseX64/dartdevk.js",
+            "-o",
+            "xcodebuild/ReleaseX64/dartdevk.js",
             "pkg/dev_compiler/bin/dartdevc.dart"
           ]
         }
@@ -1857,7 +1810,11 @@
           "script": "tools/build.py",
           "arguments": ["create_sdk"]
         },
-
+        {
+          "name": "analyze runtime/tools/dartfuzz",
+          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "arguments": ["--fatal-warnings", "runtime/tools/dartfuzz"]
+        },
         {
           "name": "analyze pkg/analysis_server",
           "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index f37da96..7fb61fe 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -14,11 +14,12 @@
    *
    * See also:
    *
-   * * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#innerhtml-on-templates>
+   * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
    */
   void setInnerHtml(String html,
     {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
     text = null;
+    content.nodes.clear();
     var fragment = createFragment(
         html, validator: validator, treeSanitizer: treeSanitizer);
 
diff --git a/tools/promote.py b/tools/promote.py
index cf31291..c9b820b 100644
--- a/tools/promote.py
+++ b/tools/promote.py
@@ -4,7 +4,7 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# Dart Editor promote tools.
+# Dart SDK promote tools.
 
 import imp
 import optparse
@@ -27,8 +27,8 @@
     promote - Will promote builds from raw/signed locations to release
               locations.
 
-    Example: Promote revision r29962 on dev channel:
-        python editor/build/promote.py promote --channel=dev --revision=29962
+    Example: Promote version 2.5.0 on the stable channel:
+        python editor/build/promote.py promote --channel=stable --version=2.5.0
   """
 
     result = optparse.OptionParser(usage=usage)
@@ -36,9 +36,15 @@
     group = optparse.OptionGroup(result, 'Promote',
                                  'options used to promote code')
     group.add_option(
-        '--revision', help='The svn revision to promote', action='store')
+        '--revision',
+        '--version',
+        help='The version to promote',
+        action='store')
     group.add_option(
-        '--channel', type='string', help='Channel to promote.', default=None)
+        '--channel',
+        type='string',
+        help='The channel to promote.',
+        default=None)
     group.add_option(
         "--dry", help='Dry run', default=False, action="store_true")
     result.add_option_group(group)
@@ -131,11 +137,20 @@
                 Gsutil(['-m', 'rm', '-R', '-f', gs_path])
                 wait_for_delete_to_be_consistent_with_list(gs_path)
 
-        # Copy sdk directory.
-        from_loc = raw_namer.sdk_directory(revision)
+        # Copy the signed sdk directory.
+        from_loc = signed_namer.sdk_directory(revision)
         to_loc = release_namer.sdk_directory(to_revision)
         remove_gs_directory(to_loc)
-        Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
+        has_signed = exists(from_loc)
+        if has_signed:
+            Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
+            # Because gsutil copies differently to existing directories, we need
+            # to use the base directory for the next recursive copy.
+            to_loc = release_namer.base_directory(to_revision)
+
+        # Copy the unsigned sdk directory without clobbering signed files.
+        from_loc = raw_namer.sdk_directory(revision)
+        Gsutil(['-m', 'cp', '-n', '-a', 'public-read', '-R', from_loc, to_loc])
 
         # Copy api-docs zipfile.
         from_loc = raw_namer.apidocs_zipfilepath(revision)
@@ -162,7 +177,7 @@
     command = [sys.executable, gsutilTool] + cmd
     if DRY_RUN:
         print "DRY runnning: %s" % command
-        return
+        return (None, None, 0)
     return bot_utils.run(command, throw_on_error=throw_on_error)
 
 
diff --git a/utils/bazel/kernel_worker.dart b/utils/bazel/kernel_worker.dart
index a0e5af3..d18212b 100644
--- a/utils/bazel/kernel_worker.dart
+++ b/utils/bazel/kernel_worker.dart
@@ -272,6 +272,12 @@
     // TODO(sigmund): add support for experiments with the incremental compiler.
     state = await fe.initializeIncrementalCompiler(
         previousState,
+        {
+          "target=$targetName",
+          "trackWidgetCreation=$trackWidgetCreation",
+          "multiRootScheme=${fileSystem.markerScheme}",
+          "multiRootRoots=${fileSystem.roots}",
+        },
         _toUri(parsedArgs['dart-sdk-summary']),
         _toUri(parsedArgs['packages-file']),
         _toUri(parsedArgs['libraries-file']),
diff --git a/utils/dart2native/BUILD.gn b/utils/dart2native/BUILD.gn
new file mode 100644
index 0000000..47712d1
--- /dev/null
+++ b/utils/dart2native/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import("../application_snapshot.gni")
+
+group("dart2native") {
+  deps = [
+    ":generate_dart2native_snapshot",
+  ]
+}
+
+application_snapshot("generate_dart2native_snapshot") {
+  main_dart = "../../pkg/dart2native/bin/dart2native.dart"
+  training_args = [
+    "--help",
+  ]
+  name = "dart2native"
+}